diff options
author | Olivier Bertrand <bertrandop@gmail.com> | 2021-05-01 22:29:38 +0200 |
---|---|---|
committer | Olivier Bertrand <bertrandop@gmail.com> | 2021-05-01 22:29:38 +0200 |
commit | ef0829ef40eb4136eed4282057baa4126dd66b69 (patch) | |
tree | 9d68776c559eaed1c6f4dd1764ebe21cd22c7bb2 | |
parent | 4df6952ce3e778c8f4d1d638350d4155281c1618 (diff) | |
download | mariadb-git-ef0829ef40eb4136eed4282057baa4126dd66b69.tar.gz |
- Major update of the json/bson/mongo table types programs.
Fix several bugs, chiefly concerning CURL operations.
modified: storage/connect/bson.cpp
modified: storage/connect/cmgfam.cpp
modified: storage/connect/cmgoconn.cpp
modified: storage/connect/cmgoconn.h
modified: storage/connect/colblk.h
modified: storage/connect/ha_connect.cc
modified: storage/connect/jmgfam.cpp
modified: storage/connect/jmgoconn.cpp
modified: storage/connect/jmgoconn.h
modified: storage/connect/json.cpp
modified: storage/connect/json.h
modified: storage/connect/mysql-test/connect/r/bson_mongo_c.result
modified: storage/connect/mysql-test/connect/r/json_mongo_c.result
modified: storage/connect/mysql-test/connect/r/mongo_c.result
modified: storage/connect/mysql-test/connect/r/mongo_java_2.result
modified: storage/connect/mysql-test/connect/r/mongo_java_3.result
modified: storage/connect/mysql-test/connect/std_data/Mongo2.jar
modified: storage/connect/mysql-test/connect/std_data/Mongo3.jar
modified: storage/connect/tabbson.cpp
modified: storage/connect/tabbson.h
modified: storage/connect/tabcmg.cpp
modified: storage/connect/tabcmg.h
modified: storage/connect/tabjmg.cpp
modified: storage/connect/tabjmg.h
modified: storage/connect/tabjson.cpp
modified: storage/connect/tabjson.h
26 files changed, 682 insertions, 403 deletions
diff --git a/storage/connect/bson.cpp b/storage/connect/bson.cpp index a0a421657bd..060e8b1e394 100644 --- a/storage/connect/bson.cpp +++ b/storage/connect/bson.cpp @@ -1205,15 +1205,14 @@ void BJSON::SetArrayValue(PBVAL bap, PBVAL nvp, int n) int i = 0; PBVAL bvp = NULL; - if (bap->To_Val) - for (bvp = GetArray(bap); bvp; i++, bvp = GetNext(bvp)) - if (i == n) { - SetValueVal(bvp, nvp); - return; - } + for (bvp = GetArray(bap); i < n; i++, bvp = bvp ? GetNext(bvp) : NULL) + if (!bvp) + AddArrayValue(bap, NewVal()); if (!bvp) AddArrayValue(bap, MOF(nvp)); + else + SetValueVal(bvp, nvp); } // end of SetValue diff --git a/storage/connect/cmgfam.cpp b/storage/connect/cmgfam.cpp index 690c087c2bb..a3afc154224 100644 --- a/storage/connect/cmgfam.cpp +++ b/storage/connect/cmgfam.cpp @@ -56,6 +56,7 @@ CMGFAM::CMGFAM(PJDEF tdp) : DOSFAM((PDOSDEF)NULL) Pcg.Coll_name = tdp->Collname; Pcg.Options = tdp->Options; Pcg.Filter = tdp->Filter; + Pcg.Line = NULL; Pcg.Pipe = tdp->Pipe && tdp->Options != NULL; Lrecl = tdp->Lrecl + tdp->Ending; } else { @@ -64,6 +65,7 @@ CMGFAM::CMGFAM(PJDEF tdp) : DOSFAM((PDOSDEF)NULL) Pcg.Coll_name = NULL; Pcg.Options = NULL; Pcg.Filter = NULL; + Pcg.Line = NULL; Pcg.Pipe = false; Lrecl = 0; } // endif tdp @@ -88,6 +90,7 @@ CMGFAM::CMGFAM(PBDEF tdp) : DOSFAM((PDOSDEF)NULL) Pcg.Coll_name = tdp->Collname; Pcg.Options = tdp->Options; Pcg.Filter = tdp->Filter; + Pcg.Line = NULL; Pcg.Pipe = tdp->Pipe && tdp->Options != NULL; Lrecl = tdp->Lrecl + tdp->Ending; } else { @@ -96,6 +99,7 @@ CMGFAM::CMGFAM(PBDEF tdp) : DOSFAM((PDOSDEF)NULL) Pcg.Coll_name = NULL; Pcg.Options = NULL; Pcg.Filter = NULL; + Pcg.Line = NULL; Pcg.Pipe = false; Lrecl = 0; } // endif tdp @@ -280,6 +284,7 @@ int CMGFAM::ReadBuffer(PGLOBAL g) /***********************************************************************/ int CMGFAM::WriteBuffer(PGLOBAL g) { + Pcg.Line = Tdbp->GetLine(); return Cmgp->Write(g); } // end of WriteBuffer diff --git a/storage/connect/cmgoconn.cpp b/storage/connect/cmgoconn.cpp index 474f940a8cf..7aa35253514 100644 --- a/storage/connect/cmgoconn.cpp +++ b/storage/connect/cmgoconn.cpp @@ -1,7 +1,7 @@ /************ CMgoConn C++ Functions Source Code File (.CPP) ***********/ -/* Name: CMgoConn.CPP Version 1.0 */ +/* Name: CMgoConn.CPP Version 1.1 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */ /* */ /* This file contains the MongoDB C connection classes functions. */ /***********************************************************************/ @@ -24,7 +24,7 @@ bool CMgoConn::IsInit = false; -bool IsNum(PSZ s); +bool IsArray(PSZ s); bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s); /* --------------------------- Class INCOL --------------------------- */ @@ -47,12 +47,13 @@ void INCOL::AddCol(PGLOBAL g, PCOL colp, char *jp) break; if (!kp) { - icp = new(g) INCOL(IsNum(p)); + icp = new(g) INCOL(); kcp = (PKC)PlugSubAlloc(g, NULL, sizeof(KEYCOL)); kcp->Next = NULL; kcp->Incolp = icp; kcp->Colp = NULL; kcp->Key = PlugDup(g, jp); + kcp->Array = IsArray(p); if (Klist) { for (kp = Klist; kp->Next; kp = kp->Next); @@ -73,6 +74,7 @@ void INCOL::AddCol(PGLOBAL g, PCOL colp, char *jp) kcp->Incolp = NULL; kcp->Colp = colp; kcp->Key = jp; + kcp->Array = IsArray(jp); if (Klist) { for (kp = Klist; kp->Next; kp = kp->Next); @@ -168,10 +170,11 @@ bool CMgoConn::Connect(PGLOBAL g) mongo_init(true); #endif // !__WIN__ - Uri = mongoc_uri_new(Pcg->Uristr); + Uri = mongoc_uri_new_with_error(Pcg->Uristr, &Error); if (!Uri) { - sprintf(g->Message, "Failed to parse URI: \"%s\"", Pcg->Uristr); + sprintf(g->Message, "Failed to parse URI: \"%s\" Msg: %s", + Pcg->Uristr, Error.message); return true; } // endif Uri @@ -228,8 +231,8 @@ bool CMgoConn::Connect(PGLOBAL g) int CMgoConn::CollSize(PGLOBAL g) { int cnt; - bson_t *query; - const char *jf = NULL; + bson_t* query; + const char* jf = NULL; if (Pcg->Pipe) return 10; @@ -237,7 +240,7 @@ int CMgoConn::CollSize(PGLOBAL g) jf = Pcg->Filter; if (jf) { - query = bson_new_from_json((const uint8_t *)jf, -1, &Error); + query = bson_new_from_json((const uint8_t*)jf, -1, &Error); if (!query) { htrc("Wrong filter: %s", Error.message); @@ -247,8 +250,17 @@ int CMgoConn::CollSize(PGLOBAL g) } else query = bson_new(); +#if defined(NDEBUG) cnt = (int)mongoc_collection_count(Collection, - MONGOC_QUERY_NONE, query, 0, 0, NULL, &Error); + MONGOC_QUERY_NONE, query, 0, 0, NULL, &Error); +#else + if (jf) + cnt = (int)mongoc_collection_count_documents(Collection, + query, NULL, NULL, NULL, &Error); + else + cnt = (int)mongoc_collection_estimated_document_count( + Collection, NULL, NULL, NULL, &Error); +#endif if (cnt < 0) { htrc("Collection count: %s", Error.message); @@ -260,30 +272,81 @@ int CMgoConn::CollSize(PGLOBAL g) } // end of CollSize /***********************************************************************/ -/* OpenDB: Data Base open routine for MONGO access method. */ +/* Project: make the projection avoid path collision. */ +/***********************************************************************/ +void CMgoConn::Project(PGLOBAL g, PSTRG s) +{ + bool m, b = false; + size_t n; + PSZ path; + PCOL cp; + PTDB tp = Pcg->Tdbp; + PTHP hp, php = NULL, * nphp = &php; + + for (cp = tp->GetColumns(); cp; cp = cp->GetNext()) { + path = cp->GetJpath(g, true); + + for (hp = php; hp; hp = hp->Next) { + if (strlen(path) < strlen(hp->Path)) { + n = strlen(path); + m = true; + } else { + n = strlen(hp->Path); + m = false; + } // endif path + + if (!strncmp(path, hp->Path, n)) + break; + + } // endfor hp + + if (!hp) { + // New path + hp = (PTHP)PlugSubAlloc(g, NULL, sizeof(PTH)); + hp->Path = path; + hp->Next = NULL; + *nphp = hp; + nphp = &hp->Next; + } else if (m) // Smaller path must replace longer one + hp->Path = path; + + } // endfor cp + + for (hp = php; hp; hp = hp->Next) { + if (b) + s->Append(",\""); + else + b = true; + + s->Append(hp->Path); + s->Append("\":1"); + } // endfor hp + +} // end of Project + +/***********************************************************************/ +/* MakeCursor: make the cursor used to retrieve documents. */ /***********************************************************************/ bool CMgoConn::MakeCursor(PGLOBAL g) { const char *p; - bool id, b = false, all = false; + bool id, all = false; PCSZ options = Pcg->Options; PTDB tp = Pcg->Tdbp; PCOL cp; PSTRG s = NULL; PFIL filp = tp->GetFilter(); - id = (tp->GetMode() != MODE_READ); + id = (tp->GetMode() == MODE_UPDATE || tp->GetMode() == MODE_DELETE); if (options && !stricmp(options, "all")) { options = NULL; all = true; - } // endif Options - - for (cp = tp->GetColumns(); cp; cp = cp->GetNext()) - if (!strcmp(cp->GetName(), "_id")) - id = true; - else if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && !options) + } else for (cp = tp->GetColumns(); cp && !all; cp = cp->GetNext()) + if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && !options) all = true; + else if (!id) + id = !strcmp(cp->GetFmt() ? cp->GetFmt() : cp->GetName(), "_id"); if (Pcg->Pipe) { if (trace(1)) @@ -311,23 +374,14 @@ bool CMgoConn::MakeCursor(PGLOBAL g) tp->SetFilter(NULL); // Not needed anymore } // endif To_Filter - if (!all && tp->GetColumns()) { + if (tp->GetColumns() && !strstr(s->GetStr(), "$project")) { // Project list s->Append(",{\"$project\":{\""); if (!id) s->Append("_id\":0,\""); - for (cp = tp->GetColumns(); cp; cp = cp->GetNext()) { - if (b) - s->Append(",\""); - else - b = true; - - s->Append(cp->GetJpath(g, true)); - s->Append("\":1"); - } // endfor cp - + Project(g, s); s->Append("}}"); } // endif all @@ -377,7 +431,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) if (MakeSelector(g, filp, s)) { strcpy(g->Message, "Failed making selector"); - return NULL; + return true; } // endif Selector tp->SetFilter(NULL); // Not needed anymore @@ -391,7 +445,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) if (!Query) { sprintf(g->Message, "Wrong filter: %s", Error.message); - return NULL; + return true; } // endif Query } else @@ -413,16 +467,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) if (!id) s->Append("_id\":0,\""); - for (cp = tp->GetColumns(); cp; cp = cp->GetNext()) { - if (b) - s->Append(",\""); - else - b = true; - - s->Append(cp->GetJpath(g, true)); - s->Append("\":1"); - } // endfor cp - + Project(g, s); s->Append("}}"); s->Resize(s->GetLength() + 1); p = s->GetStr(); @@ -435,7 +480,7 @@ bool CMgoConn::MakeCursor(PGLOBAL g) if (!Opts) { sprintf(g->Message, "Wrong options: %s", Error.message); - return NULL; + return true; } // endif Opts } // endif all @@ -495,44 +540,54 @@ void CMgoConn::ShowDocument(bson_iter_t *iter, const bson_t *doc, const char *k) key = bson_iter_key(iter); htrc("Found element key: \"%s\"\n", key); - if (BSON_ITER_HOLDS_UTF8(iter)) - htrc("%s.%s=\"%s\"\n", k, key, bson_iter_utf8(iter, NULL)); - else if (BSON_ITER_HOLDS_INT32(iter)) - htrc("%s.%s=%d\n", k, key, bson_iter_int32(iter)); - else if (BSON_ITER_HOLDS_INT64(iter)) - htrc("%s.%s=%lld\n", k, key, bson_iter_int64(iter)); - else if (BSON_ITER_HOLDS_DOUBLE(iter)) - htrc("%s.%s=%g\n", k, key, bson_iter_double(iter)); - else if (BSON_ITER_HOLDS_DATE_TIME(iter)) - htrc("%s.%s=date(%lld)\n", k, key, bson_iter_date_time(iter)); - else if (BSON_ITER_HOLDS_OID(iter)) { - char str[25]; - - bson_oid_to_string(bson_iter_oid(iter), str); - htrc("%s.%s=%s\n", k, key, str); - } else if (BSON_ITER_HOLDS_DECIMAL128(iter)) { - char *str = NULL; - bson_decimal128_t dec; - - bson_iter_decimal128(iter, &dec); - bson_decimal128_to_string(&dec, str); - htrc("%s.%s=%s\n", k, key, str); - } else if (BSON_ITER_HOLDS_DOCUMENT(iter)) { - bson_iter_t child; - - if (bson_iter_recurse(iter, &child)) - ShowDocument(&child, NULL, key); - - } else if (BSON_ITER_HOLDS_ARRAY(iter)) { - bson_t *arr; - bson_iter_t itar; - const uint8_t *data = NULL; - uint32_t len = 0; - - bson_iter_array(iter, &len, &data); - arr = bson_new_from_data(data, len); - ShowDocument(&itar, arr, key); - } // endif's + switch (bson_iter_type(iter)) { + case BSON_TYPE_UTF8: + htrc("%s.%s=\"%s\"\n", k, key, bson_iter_utf8(iter, NULL)); + break; + case BSON_TYPE_INT32: + htrc("%s.%s=%d\n", k, key, bson_iter_int32(iter)); + break; + case BSON_TYPE_INT64: + htrc("%s.%s=%lld\n", k, key, bson_iter_int64(iter)); + break; + case BSON_TYPE_DOUBLE: + htrc("%s.%s=%g\n", k, key, bson_iter_double(iter)); + break; + case BSON_TYPE_DATE_TIME: + htrc("%s.%s=date(%lld)\n", k, key, bson_iter_date_time(iter)); + break; + case BSON_TYPE_OID: { + char str[25]; + + bson_oid_to_string(bson_iter_oid(iter), str); + htrc("%s.%s=%s\n", k, key, str); + } break; + case BSON_TYPE_DECIMAL128: { + char* str = NULL; + bson_decimal128_t dec; + + bson_iter_decimal128(iter, &dec); + bson_decimal128_to_string(&dec, str); + htrc("%s.%s=%s\n", k, key, str); + } break; + case BSON_TYPE_DOCUMENT: { + bson_iter_t child; + + if (bson_iter_recurse(iter, &child)) + ShowDocument(&child, NULL, key); + + } break; + case BSON_TYPE_ARRAY: { + bson_t* arr; + bson_iter_t itar; + const uint8_t* data = NULL; + uint32_t len = 0; + + bson_iter_array(iter, &len, &data); + arr = bson_new_from_data(data, len); + ShowDocument(&itar, arr, key); + } break; + } // endswitch iter } // endwhile bson_iter_next @@ -545,7 +600,7 @@ void CMgoConn::ShowDocument(bson_iter_t *iter, const bson_t *doc, const char *k) /***********************************************************************/ void CMgoConn::MakeColumnGroups(PGLOBAL g) { - Fpc = new(g) INCOL(false); + Fpc = new(g) INCOL(); for (PCOL colp = Pcg->Tdbp->GetColumns(); colp; colp = colp->GetNext()) if (!colp->IsSpecial()) @@ -560,7 +615,7 @@ bool CMgoConn::DocWrite(PGLOBAL g, PINCOL icp) { for (PKC kp = icp->Klist; kp; kp = kp->Next) if (kp->Incolp) { - bool isdoc = !kp->Incolp->Array; + bool isdoc = !kp->Array; if (isdoc) BSON_APPEND_DOCUMENT_BEGIN(icp->Child, kp->Key, kp->Incolp->Child); @@ -582,7 +637,7 @@ bool CMgoConn::DocWrite(PGLOBAL g, PINCOL icp) } // end of DocWrite /***********************************************************************/ -/* WriteDB: Data Base write routine for DOS access method. */ +/* WriteDB: Data Base write routine for CMGO access method. */ /***********************************************************************/ int CMgoConn::Write(PGLOBAL g) { @@ -590,22 +645,45 @@ int CMgoConn::Write(PGLOBAL g) PTDB tp = Pcg->Tdbp; if (tp->GetMode() == MODE_INSERT) { - Fpc->Init(); + if (!Pcg->Line) { + Fpc->Init(); - if (DocWrite(g, Fpc)) - return RC_FX; + if (DocWrite(g, Fpc)) + return RC_FX; - if (trace(2)) { - char *str = bson_as_json(Fpc->Child, NULL); - htrc("Inserting: %s\n", str); - bson_free(str); - } // endif trace + if (trace(2)) { + char* str = bson_as_json(Fpc->Child, NULL); + htrc("Inserting: %s\n", str); + bson_free(str); + } // endif trace - if (!mongoc_collection_insert(Collection, MONGOC_INSERT_NONE, - Fpc->Child, NULL, &Error)) { - sprintf(g->Message, "Mongo insert: %s", Error.message); - rc = RC_FX; - } // endif insert + if (!mongoc_collection_insert(Collection, MONGOC_INSERT_NONE, + Fpc->Child, NULL, &Error)) { + sprintf(g->Message, "Mongo insert: %s", Error.message); + rc = RC_FX; + } // endif insert + + } else { + const uint8_t* val = (const uint8_t*)Pcg->Line; + bson_t* doc = bson_new_from_json(val, -1, &Error); + + if (doc && trace(2)) { + char* str = bson_as_json(doc, NULL); + htrc("Inserting: %s\n", str); + bson_free(str); + } // endif trace + + if (!doc) { + sprintf(g->Message, "bson_new_from_json: %s", Error.message); + rc = RC_FX; + } else if (!mongoc_collection_insert(Collection, + MONGOC_INSERT_NONE, doc, NULL, &Error)) { + sprintf(g->Message, "Mongo insert: %s", Error.message); + bson_destroy(doc); + rc = RC_FX; + } // endif insert + + } // endif Line } else { bool b = false; @@ -614,19 +692,26 @@ int CMgoConn::Write(PGLOBAL g) bson_iter_init(&iter, Document); - if (bson_iter_find(&iter, "_id")) { - if (BSON_ITER_HOLDS_OID(&iter)) - b = BSON_APPEND_OID(query, "_id", bson_iter_oid(&iter)); - else if (BSON_ITER_HOLDS_INT32(&iter)) - b = BSON_APPEND_INT32(query, "_id", bson_iter_int32(&iter)); - else if (BSON_ITER_HOLDS_INT64(&iter)) - b = BSON_APPEND_INT64(query, "_id", bson_iter_int64(&iter)); - else if (BSON_ITER_HOLDS_DOUBLE(&iter)) - b = BSON_APPEND_DOUBLE(query, "_id", bson_iter_double(&iter)); - else if (BSON_ITER_HOLDS_UTF8(&iter)) - b = BSON_APPEND_UTF8(query, "_id", bson_iter_utf8(&iter, NULL)); - - } // endif iter + if (bson_iter_find(&iter, "_id")) + switch (bson_iter_type(&iter)) { + case BSON_TYPE_OID: + b = BSON_APPEND_OID(query, "_id", bson_iter_oid(&iter)); + break; + case BSON_TYPE_UTF8: + b = BSON_APPEND_UTF8(query, "_id", bson_iter_utf8(&iter, NULL)); + break; + case BSON_TYPE_INT32: + b = BSON_APPEND_INT32(query, "_id", bson_iter_int32(&iter)); + break; + case BSON_TYPE_INT64: + b = BSON_APPEND_INT64(query, "_id", bson_iter_int64(&iter)); + break; + case BSON_TYPE_DOUBLE: + b = BSON_APPEND_DOUBLE(query, "_id", bson_iter_double(&iter)); + break; + default: + break; + } // endswitch iter if (b) { if (trace(2)) { @@ -721,7 +806,7 @@ void CMgoConn::Close(void) char *CMgoConn::Mini(PGLOBAL g, PCOL colp, const bson_t *bson, bool b) { char *s, *str = NULL; - char *Mbuf = (char*)PlugSubAlloc(g, NULL, colp->GetLength() + 1); + char *Mbuf = (char*)PlugSubAlloc(g, NULL, (size_t)colp->GetLength() + 1); int i, k = 0; bool ok = true; @@ -759,97 +844,100 @@ char *CMgoConn::Mini(PGLOBAL g, PCOL colp, const bson_t *bson, bool b) /***********************************************************************/ void CMgoConn::GetColumnValue(PGLOBAL g, PCOL colp) { - char *jpath = colp->GetJpath(g, false); - PVAL value = colp->GetValue(); + char *jpath = colp->GetJpath(g, false); + bool b = false; + PVAL value = colp->GetValue(); + bson_iter_t Iter; // Used to retrieve column value + bson_iter_t Desc; // Descendant iter - if (!strcmp(jpath, "*")) { + if (!*jpath || !strcmp(jpath, "*")) { value->SetValue_psz(Mini(g, colp, Document, false)); } else if (bson_iter_init(&Iter, Document) && bson_iter_find_descendant(&Iter, jpath, &Desc)) { - if (BSON_ITER_HOLDS_UTF8(&Desc)) - value->SetValue_psz((PSZ)bson_iter_utf8(&Desc, NULL)); - else if (BSON_ITER_HOLDS_INT32(&Desc)) - value->SetValue(bson_iter_int32(&Desc)); - else if (BSON_ITER_HOLDS_INT64(&Desc)) - value->SetValue(bson_iter_int64(&Desc)); - else if (BSON_ITER_HOLDS_DOUBLE(&Desc)) - value->SetValue(bson_iter_double(&Desc)); - else if (BSON_ITER_HOLDS_DATE_TIME(&Desc)) - value->SetValue(bson_iter_date_time(&Desc) / 1000); - else if (BSON_ITER_HOLDS_BOOL(&Desc)) { - bool b = bson_iter_bool(&Desc); - - if (value->IsTypeNum()) - value->SetValue(b ? 1 : 0); - else - value->SetValue_psz(b ? "true" : "false"); - - } else if (BSON_ITER_HOLDS_OID(&Desc)) { - char str[25]; - - bson_oid_to_string(bson_iter_oid(&Desc), str); - value->SetValue_psz(str); - } else if (BSON_ITER_HOLDS_NULL(&Iter)) { - // Apparently this does not work... - value->Reset(); - value->SetNull(true); - } else if (BSON_ITER_HOLDS_DECIMAL128(&Desc)) { - char *str = NULL; - bson_decimal128_t dec; - - bson_iter_decimal128(&Desc, &dec); - bson_decimal128_to_string(&dec, str); - value->SetValue_psz(str); - bson_free(str); - } else if (BSON_ITER_HOLDS_DOCUMENT(&Iter)) { - bson_t *doc; - const uint8_t *data = NULL; - uint32_t len = 0; - - bson_iter_document(&Desc, &len, &data); - - if (data) { - doc = bson_new_from_data(data, len); - value->SetValue_psz(Mini(g, colp, doc, false)); - bson_destroy(doc); - } else { - // ... but we can come here in case of NULL! - value->Reset(); - value->SetNull(true); - } // endif data + switch (bson_iter_type(&Desc)) { + case BSON_TYPE_UTF8: + value->SetValue_psz((PSZ)bson_iter_utf8(&Desc, NULL)); + break; + case BSON_TYPE_INT32: + value->SetValue(bson_iter_int32(&Desc)); + break; + case BSON_TYPE_INT64: + value->SetValue(bson_iter_int64(&Desc)); + break; + case BSON_TYPE_DOUBLE: + value->SetValue(bson_iter_double(&Desc)); + break; + case BSON_TYPE_DATE_TIME: + value->SetValue(bson_iter_date_time(&Desc) / 1000); + break; + case BSON_TYPE_BOOL: + b = bson_iter_bool(&Desc); - } else if (BSON_ITER_HOLDS_ARRAY(&Iter)) { - bson_t *arr; - const uint8_t *data = NULL; - uint32_t len = 0; + if (value->IsTypeNum()) + value->SetValue(b ? 1 : 0); + else + value->SetValue_psz(b ? "true" : "false"); - bson_iter_array(&Desc, &len, &data); + break; + case BSON_TYPE_OID: { + char str[25]; - if (data) { - arr = bson_new_from_data(data, len); - value->SetValue_psz(Mini(g, colp, arr, true)); - bson_destroy(arr); - } else { - // This is a bug in returning the wrong type - // This fix is only for document items - bson_t *doc; + bson_oid_to_string(bson_iter_oid(&Desc), str); + value->SetValue_psz(str); + } break; + case BSON_TYPE_ARRAY: + b = true; + // passthru + case BSON_TYPE_DOCUMENT: + { // All this because MongoDB can return the wrong type + int i = 0; + const uint8_t *data = NULL; + uint32_t len = 0; + + for (; i < 2; i++) { + if (b) // Try array first + bson_iter_array(&Desc, &len, &data); + else + bson_iter_document(&Desc, &len, &data); - bson_iter_document(&Desc, &len, &data); + if (!data) { + len = 0; + b = !b; + } else + break; + + } // endfor i if (data) { - doc = bson_new_from_data(data, len); - value->SetValue_psz(Mini(g, colp, doc, false)); + bson_t *doc = bson_new_from_data(data, len); + + value->SetValue_psz(Mini(g, colp, doc, b)); bson_destroy(doc); } else { // ... or we can also come here in case of NULL! value->Reset(); value->SetNull(true); - } // endif data + } // endif data - } // endif data + } break; + case BSON_TYPE_NULL: + // Apparently this does not work... + value->Reset(); + value->SetNull(true); + break; + case BSON_TYPE_DECIMAL128: { + char* str = NULL; + bson_decimal128_t dec; - } else - value->Reset(); + bson_iter_decimal128(&Desc, &dec); + bson_decimal128_to_string(&dec, str); + value->SetValue_psz(str); + bson_free(str); + } break; + default: + value->Reset(); + break; + } // endswitch Desc } else { // Field does not exist @@ -875,7 +963,28 @@ bool CMgoConn::AddValue(PGLOBAL g, PCOL colp, bson_t *doc, char *key, bool upd) } else switch (colp->GetResultType()) { case TYPE_STRING: - rc = BSON_APPEND_UTF8(doc, key, value->GetCharValue()); + if (colp->Stringify()) { + const uint8_t *val = (const uint8_t*)value->GetCharValue(); + bson_t *bsn = bson_new_from_json(val, -1, &Error); + + if (!bsn) { + sprintf (g->Message, "AddValue: %s", Error.message); + return true; + } else if (*key) { + if (*val == '[') + rc = BSON_APPEND_ARRAY(doc, key, bsn); + else + rc = BSON_APPEND_DOCUMENT(doc, key, bsn); + + } else { + bson_copy_to (bsn, doc); + rc = true; + } // endif's + + bson_free(bsn); + } else + rc = BSON_APPEND_UTF8(doc, key, value->GetCharValue()); + break; case TYPE_INT: case TYPE_SHORT: diff --git a/storage/connect/cmgoconn.h b/storage/connect/cmgoconn.h index b1216ac576c..5c9fb4f763d 100644 --- a/storage/connect/cmgoconn.h +++ b/storage/connect/cmgoconn.h @@ -28,11 +28,8 @@ typedef struct mongo_parms { PCSZ Coll_name; PCSZ Options; PCSZ Filter; + PCSZ Line; bool Pipe; -//PCSZ User; // User connect info -//PCSZ Pwd; // Password connect info -//int Fsize; // Fetch size -//bool Scrollable; // Scrollable cursor } CMGOPARM, *PCPARM; typedef struct KEYCOL { @@ -40,15 +37,23 @@ typedef struct KEYCOL { PINCOL Incolp; PCOL Colp; char *Key; + bool Array; } *PKC; +typedef struct _path_list *PTHP; + +typedef struct _path_list { + PSZ Path; + PTHP Next; +} PTH; + /***********************************************************************/ /* Used when inserting values in a MongoDB collection. */ /***********************************************************************/ class INCOL : public BLOCK { public: // Constructor - INCOL(bool ar) { Child = bson_new(); Klist = NULL; Array = ar; } + INCOL(void) { Child = bson_new(); Klist = NULL; } // Methods void AddCol(PGLOBAL g, PCOL colp, char *jp); @@ -58,7 +63,6 @@ public: //Members bson_t *Child; PKC Klist; - bool Array; }; // end of INCOL; /***********************************************************************/ @@ -80,6 +84,7 @@ public: bool IsConnected(void) { return m_Connected; } bool Connect(PGLOBAL g); int CollSize(PGLOBAL g); + void CMgoConn::Project(PGLOBAL g, PSTRG s); bool MakeCursor(PGLOBAL g); int ReadNext(PGLOBAL g); PSZ GetDocument(PGLOBAL g); @@ -108,8 +113,6 @@ protected: bson_t *Query; // MongoDB cursor filter bson_t *Opts; // MongoDB cursor options bson_error_t Error; - bson_iter_t Iter; // Used to retrieve column value - bson_iter_t Desc; // Descendant iter PINCOL Fpc; // To insert INCOL classes PFBLOCK fp; bool m_Connected; diff --git a/storage/connect/colblk.h b/storage/connect/colblk.h index b22933d9ebb..f303528f982 100644 --- a/storage/connect/colblk.h +++ b/storage/connect/colblk.h @@ -38,7 +38,8 @@ class DllExport COLBLK : public XOBJECT { virtual PTDB GetTo_Tdb(void) {return To_Tdb;} virtual int GetClustered(void) {return 0;} virtual int IsClustered(void) {return FALSE;} - virtual PSZ GetJpath(PGLOBAL g, bool proj) {return NULL;} + virtual bool Stringify(void) {return FALSE;} + virtual PSZ GetJpath(PGLOBAL g, bool proj) {return NULL;} PCOL GetNext(void) {return Next;} PSZ GetName(void) {return Name;} int GetIndex(void) {return Index;} diff --git a/storage/connect/ha_connect.cc b/storage/connect/ha_connect.cc index b3c0b0c69b2..f85035d6e06 100644 --- a/storage/connect/ha_connect.cc +++ b/storage/connect/ha_connect.cc @@ -5470,14 +5470,13 @@ static bool add_field(String* sql, TABTYPE ttp, const char* field_name, int typ, } // endif rem if (fmt && *fmt) { - switch (ttp) { - case TAB_JSON: error |= sql->append(" JPATH='"); break; -#if defined(BSON_SUPPORT) - case TAB_BSON: error |= sql->append(" JPATH='"); break; -#endif // BSON_SUPPORT - case TAB_XML: error |= sql->append(" XPATH='"); break; - default: error |= sql->append(" FIELD_FORMAT='"); - } // endswitch ttp + switch (ttp) { + case TAB_MONGO: + case TAB_BSON: + case TAB_JSON: error |= sql->append(" JPATH='"); break; + case TAB_XML: error |= sql->append(" XPATH='"); break; + default: error |= sql->append(" FIELD_FORMAT='"); + } // endswitch ttp error |= sql->append_for_single_quote(fmt, strlen(fmt)); error |= sql->append("'"); diff --git a/storage/connect/jmgfam.cpp b/storage/connect/jmgfam.cpp index 2d45753ec63..d7f469cf4fe 100644 --- a/storage/connect/jmgfam.cpp +++ b/storage/connect/jmgfam.cpp @@ -1,11 +1,11 @@ /************ JMONGO FAM C++ Program Source Code File (.CPP) ***********/ /* PROGRAM NAME: jmgfam.cpp */ /* ------------- */ -/* Version 1.1 */ +/* Version 1.2 */ /* */ /* COPYRIGHT: */ /* ---------- */ -/* (C) Copyright to the author Olivier BERTRAND 20017 - 2020 */ +/* (C) Copyright to the author Olivier BERTRAND 20017 - 2021 */ /* */ /* WHAT THIS PROGRAM DOES: */ /* ----------------------- */ @@ -241,8 +241,8 @@ bool JMGFAM::OpenTableFile(PGLOBAL g) return true; } // endif Mode - if (Mode == MODE_INSERT) - Jcp->MakeColumnGroups(g, Tdbp); +//if (Mode == MODE_INSERT) +// Jcp->MakeColumnGroups(g, Tdbp); if (Mode != MODE_UPDATE) return Jcp->MakeCursor(g, Tdbp, Options, Filter, Pipe); @@ -346,14 +346,14 @@ int JMGFAM::ReadBuffer(PGLOBAL g) } // end of ReadBuffer /***********************************************************************/ -/* WriteBuffer: File write routine for MGO access method. */ +/* WriteBuffer: File write routine for JMG access method. */ /***********************************************************************/ int JMGFAM::WriteBuffer(PGLOBAL g) { int rc = RC_OK; if (Mode == MODE_INSERT) { - rc = Jcp->DocWrite(g); + rc = Jcp->DocWrite(g, Tdbp->GetLine()); } else if (Mode == MODE_DELETE) { rc = Jcp->DocDelete(g, false); } else if (Mode == MODE_UPDATE) { diff --git a/storage/connect/jmgoconn.cpp b/storage/connect/jmgoconn.cpp index 0af91bc78cd..a4091e88bbf 100644 --- a/storage/connect/jmgoconn.cpp +++ b/storage/connect/jmgoconn.cpp @@ -1,7 +1,7 @@ /************ JMgoConn C++ Functions Source Code File (.CPP) ***********/ -/* Name: JMgoConn.CPP Version 1.1 */ +/* Name: JMgoConn.CPP Version 1.2 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */ /* */ /* This file contains the MongoDB Java connection classes functions. */ /***********************************************************************/ @@ -24,7 +24,7 @@ #define nullptr 0 -bool IsNum(PSZ s); +bool IsArray(PSZ s); bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s); /* --------------------------- Class JNCOL --------------------------- */ @@ -43,19 +43,21 @@ void JNCOL::AddCol(PGLOBAL g, PCOL colp, PSZ jp) *p++ = 0; for (kp = Klist; kp; kp = kp->Next) - if (kp->Jncolp && !strcmp(jp, kp->Key)) + if (kp->Jncolp && ((kp->Key && !strcmp(jp, kp->Key)) + || (!kp->Key && IsArray(jp) && kp->N == atoi(jp)))) break; if (!kp) { - icp = new(g) JNCOL(IsNum(p)); + icp = new(g) JNCOL(); kcp = (PJKC)PlugSubAlloc(g, NULL, sizeof(JKCOL)); kcp->Next = NULL; kcp->Jncolp = icp; kcp->Colp = NULL; + kcp->Array = IsArray(jp); - if (Array) { + if (kcp->Array) { kcp->Key = NULL; - kcp->N = atoi(p); + kcp->N = atoi(jp); } else { kcp->Key = PlugDup(g, jp); kcp->N = 0; @@ -75,12 +77,12 @@ void JNCOL::AddCol(PGLOBAL g, PCOL colp, PSZ jp) icp->AddCol(g, colp, p); } else { kcp = (PJKC)PlugSubAlloc(g, NULL, sizeof(JKCOL)); - kcp->Next = NULL; kcp->Jncolp = NULL; kcp->Colp = colp; + kcp->Array = IsArray(jp); - if (Array) { + if (kcp->Array) { kcp->Key = NULL; kcp->N = atoi(jp); } else { @@ -108,7 +110,7 @@ JMgoConn::JMgoConn(PGLOBAL g, PCSZ collname, PCSZ wrapper) CollName = collname; readid = fetchid = getdocid = objfldid = fcollid = acollid = mkdocid = docaddid = mkarid = araddid = insertid = updateid = - deleteid = gcollid = countid = rewindid = nullptr; + deleteid = gcollid = countid = rewindid = mkbsonid = nullptr; DiscFunc = "MongoDisconnect"; Fpc = NULL; m_Fetch = 0; @@ -235,7 +237,7 @@ bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, PCSZ filter, bool pipe) { const char *p; - bool b = false, id = (tdbp->GetMode() != MODE_READ), all = false; + bool id, b = false, all = false; uint len; PCOL cp; PSZ jp; @@ -246,13 +248,14 @@ bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, if (Options && !stricmp(Options, "all")) { Options = NULL; all = true; - } // endif Options + } else + id = (tdbp->GetMode() == MODE_UPDATE || tdbp->GetMode() == MODE_DELETE); - for (cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) - if (!strcmp(cp->GetName(), "_id")) - id = true; - else if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && (!Options || pipe)) + for (cp = tdbp->GetColumns(); cp && !all; cp = cp->GetNext()) + if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*") && (!Options || pipe)) all = true; + else if (!id) + id = !strcmp(cp->GetJpath(g, false), "_id"); if (pipe && Options) { if (trace(1)) @@ -535,7 +538,7 @@ PSZ JMgoConn::GetDocument(void) /***********************************************************************/ void JMgoConn::MakeColumnGroups(PGLOBAL g, PTDB tdbp) { - Fpc = new(g) JNCOL(false); + Fpc = new(g) JNCOL(); for (PCOL colp = tdbp->GetColumns(); colp; colp = colp->GetNext()) if (!colp->IsSpecial()) @@ -553,7 +556,7 @@ bool JMgoConn::GetMethodId(PGLOBAL g, MODE mode) return true; if (gmID(g, docaddid, "DocAdd", - "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z")) + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;I)Z")) return true; if (gmID(g, updateid, "CollUpdate", "(Ljava/lang/Object;)J")) @@ -563,14 +566,19 @@ bool JMgoConn::GetMethodId(PGLOBAL g, MODE mode) if (gmID(g, mkdocid, "MakeDocument", "()Ljava/lang/Object;")) return true; + if (gmID(g, mkbsonid, "MakeBson", + "(Ljava/lang/String;I)Ljava/lang/Object;")) + return true; + if (gmID(g, docaddid, "DocAdd", - "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z")) + "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;I)Z")) return true; if (gmID(g, mkarid, "MakeArray", "()Ljava/lang/Object;")) return true; - if (gmID(g, araddid, "ArrayAdd", "(Ljava/lang/Object;ILjava/lang/Object;)Z")) + if (gmID(g, araddid, "ArrayAdd", + "(Ljava/lang/Object;ILjava/lang/Object;I)Z")) return true; if (gmID(g, insertid, "CollInsert", "(Ljava/lang/Object;)Z")) @@ -639,48 +647,81 @@ jobject JMgoConn::MakeObject(PGLOBAL g, PCOL colp, bool&error ) } // end of MakeObject /***********************************************************************/ +/* Stringify. */ +/***********************************************************************/ +bool JMgoConn::Stringify(PCOL colp) +{ + bool b = false; + + if (colp) + b = (colp->Stringify() && colp->GetResultType() == TYPE_STRING); + + return b; +} // end of Stringify + +/***********************************************************************/ /* MakeDoc. */ /***********************************************************************/ jobject JMgoConn::MakeDoc(PGLOBAL g, PJNCOL jcp) { - bool error = false; + int j; + bool b, error = false; jobject parent, child, val; jstring jkey; - - if (jcp->Array) + PJKC kp = jcp->Klist; + + if (kp->Array) parent = env->CallObjectMethod(job, mkarid); else parent = env->CallObjectMethod(job, mkdocid); - for (PJKC kp = jcp->Klist; kp; kp = kp->Next) + for (j = 0; kp; j = 0, kp = kp->Next) { + if (Stringify(kp->Colp)) { + switch (*kp->Colp->GetCharValue()) { + case '{': j = 1; break; + case '[': j = 2; break; + default: break; + } // endswitch + + b = (!kp->Key || !*kp->Key || *kp->Key == '*'); + } else + b = false; + if (kp->Jncolp) { if (!(child = MakeDoc(g, kp->Jncolp))) return NULL; - if (!jcp->Array) { + if (!kp->Array) { jkey = env->NewStringUTF(kp->Key); - if (env->CallBooleanMethod(job, docaddid, parent, jkey, child)) + if (env->CallBooleanMethod(job, docaddid, parent, jkey, child, j)) return NULL; env->DeleteLocalRef(jkey); } else - if (env->CallBooleanMethod(job, araddid, parent, kp->N, child)) + if (env->CallBooleanMethod(job, araddid, parent, kp->N, child, j)) return NULL; + env->DeleteLocalRef(child); } else { if (!(val = MakeObject(g, kp->Colp, error))) { if (error) return NULL; - } else if (!jcp->Array) { - jkey = env->NewStringUTF(kp->Key); + } else if (!kp->Array) { + if (!b) { + jkey = env->NewStringUTF(kp->Key); - if (env->CallBooleanMethod(job, docaddid, parent, jkey, val)) - return NULL; + if (env->CallBooleanMethod(job, docaddid, parent, jkey, val, j)) + return NULL; - env->DeleteLocalRef(jkey); - } else if (env->CallBooleanMethod(job, araddid, parent, kp->N, val)) { + env->DeleteLocalRef(jkey); + } else { + env->DeleteLocalRef(parent); + parent = env->CallObjectMethod(job, mkbsonid, val, j); + } // endif b + + } else if (env->CallBooleanMethod(job, araddid, parent, kp->N, val, j)) { if (Check(-1)) sprintf(g->Message, "ArrayAdd: %s", Msg); else @@ -689,19 +730,38 @@ jobject JMgoConn::MakeDoc(PGLOBAL g, PJNCOL jcp) return NULL; } // endif ArrayAdd + env->DeleteLocalRef(val); } // endif Jncolp + } // endfor kp + return parent; } // end of MakeDoc /***********************************************************************/ /* Insert a new document in the collation. */ /***********************************************************************/ -int JMgoConn::DocWrite(PGLOBAL g) +int JMgoConn::DocWrite(PGLOBAL g, PCSZ line) { - jobject doc; + int rc = RC_OK; + jobject doc = nullptr; + + if (line) { + int j; + jobject val = env->NewStringUTF(line); - if (!Fpc || !(doc = MakeDoc(g, Fpc))) + switch (*line) { + case '{': j = 1; break; + case '[': j = 2; break; + default: j = 0; break; + } // endswitch line + + doc = env->CallObjectMethod(job, mkbsonid, val, j); + env->DeleteLocalRef(val); + } else if (Fpc) + doc = MakeDoc(g, Fpc); + + if (!doc) return RC_FX; if (env->CallBooleanMethod(job, insertid, doc)) { @@ -710,10 +770,11 @@ int JMgoConn::DocWrite(PGLOBAL g) else sprintf(g->Message, "CollInsert: unknown error"); - return RC_FX; + rc = RC_FX; } // endif Insert - return RC_OK; + env->DeleteLocalRef(doc); + return rc; } // end of DocWrite /***********************************************************************/ @@ -721,7 +782,7 @@ int JMgoConn::DocWrite(PGLOBAL g) /***********************************************************************/ int JMgoConn::DocUpdate(PGLOBAL g, PTDB tdbp) { - int rc = RC_OK; + int j = 0, rc = RC_OK; bool error; PCOL colp; jstring jkey; @@ -734,8 +795,14 @@ int JMgoConn::DocUpdate(PGLOBAL g, PTDB tdbp) if (error) return RC_FX; - - if (env->CallBooleanMethod(job, docaddid, updlist, jkey, val)) + else if (Stringify(colp)) + switch (*colp->GetCharValue()) { + case '{': j = 1; break; + case '[': j = 2; break; + default: break; + } // endswitch + + if (env->CallBooleanMethod(job, docaddid, updlist, jkey, val, j)) return RC_OK; env->DeleteLocalRef(jkey); @@ -745,7 +812,7 @@ int JMgoConn::DocUpdate(PGLOBAL g, PTDB tdbp) upd = env->CallObjectMethod(job, mkdocid); jkey = env->NewStringUTF("$set"); - if (env->CallBooleanMethod(job, docaddid, upd, jkey, updlist)) + if (env->CallBooleanMethod(job, docaddid, upd, jkey, updlist, 0)) return RC_OK; env->DeleteLocalRef(jkey); diff --git a/storage/connect/jmgoconn.h b/storage/connect/jmgoconn.h index 8ee7985d760..9fed1907abc 100644 --- a/storage/connect/jmgoconn.h +++ b/storage/connect/jmgoconn.h @@ -25,6 +25,7 @@ typedef struct JKCOL { PCOL Colp; char *Key; int N; + bool Array; } *PJKC; /***********************************************************************/ @@ -33,18 +34,18 @@ typedef struct JKCOL { class JNCOL : public BLOCK { public: // Constructor - JNCOL(bool ar) { Klist = NULL; Array = ar; } +//JNCOL(bool ar) { Klist = NULL; Array = ar; } + JNCOL(void) { Klist = NULL; } // Methods void AddCol(PGLOBAL g, PCOL colp, PSZ jp); //Members PJKC Klist; - bool Array; }; // end of JNCOL; /***********************************************************************/ -/* JMgoConn class. */ +/* JMgoConn class. */ /***********************************************************************/ class JMgoConn : public JAVAConn { friend class TDBJMG; @@ -81,11 +82,12 @@ public: bool GetMethodId(PGLOBAL g, MODE mode); jobject MakeObject(PGLOBAL g, PCOL colp, bool& error); jobject MakeDoc(PGLOBAL g, PJNCOL jcp); - int DocWrite(PGLOBAL g); + int DocWrite(PGLOBAL g, PCSZ line); int DocUpdate(PGLOBAL g, PTDB tdbp); int DocDelete(PGLOBAL g, bool all); bool Rewind(void); PSZ GetDocument(void); + bool Stringify(PCOL colp); protected: // Members @@ -100,6 +102,7 @@ protected: jmethodID getdocid; // The GetDoc method ID jmethodID objfldid; // The ObjectField method ID jmethodID mkdocid; // The MakeDocument method ID + jmethodID mkbsonid; // The MakeBson method ID jmethodID docaddid; // The DocAdd method ID jmethodID mkarid; // The MakeArray method ID jmethodID araddid; // The ArrayAdd method ID diff --git a/storage/connect/json.cpp b/storage/connect/json.cpp index f65294429db..b1f9f10957b 100644 --- a/storage/connect/json.cpp +++ b/storage/connect/json.cpp @@ -78,6 +78,24 @@ bool IsNum(PSZ s) } // end of IsNum /***********************************************************************/ +/* IsArray: check whether this is a Mongo array path. */ +/***********************************************************************/ +bool IsArray(PSZ s) +{ + char* p = s; + + if (!p || !*p) + return false; + else for (; *p; p++) + if (*p == '.') + break; + else if (!isdigit(*p)) + return false; + + return true; +} // end of IsArray + +/***********************************************************************/ /* NextChr: return the first found '[' or Sep pointer. */ /***********************************************************************/ char* NextChr(PSZ s, char sep) @@ -1326,9 +1344,9 @@ bool JARRAY::Merge(PGLOBAL g, PJSON jsp) } // end of Merge /***********************************************************************/ -/* Set the nth Value of the Array Value list. */ +/* Set the nth Value of the Array Value list or add it. */ /***********************************************************************/ -bool JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n) +void JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n) { int i = 0; PJVAL jp, *jpp = &First; @@ -1339,7 +1357,6 @@ bool JARRAY::SetArrayValue(PGLOBAL g, PJVAL jvp, int n) *jpp = jvp; jvp->Next = (jp ? jp->Next : NULL); - return false; } // end of SetValue /***********************************************************************/ @@ -1417,7 +1434,7 @@ bool JARRAY::IsNull(void) /***********************************************************************/ JVALUE::JVALUE(PJSON jsp) : JSON() { - if (jsp->GetType() == TYPE_JVAL) { + if (jsp && jsp->GetType() == TYPE_JVAL) { PJVAL jvp = (PJVAL)jsp; // Val = ((PJVAL)jsp)->GetVal(); @@ -1434,7 +1451,7 @@ JVALUE::JVALUE(PJSON jsp) : JSON() } else { Jsp = jsp; // Val = NULL; - DataType = TYPE_JSON; + DataType = Jsp ? TYPE_JSON : TYPE_NULL; Nd = 0; } // endif Type diff --git a/storage/connect/json.h b/storage/connect/json.h index 3a026f5df22..ef5f6c7b7de 100644 --- a/storage/connect/json.h +++ b/storage/connect/json.h @@ -184,7 +184,7 @@ class JARRAY : public JSON { // Specific PJVAL AddArrayValue(PGLOBAL g, PJVAL jvp = NULL, int* x = NULL); - bool SetArrayValue(PGLOBAL g, PJVAL jvp, int i); + void SetArrayValue(PGLOBAL g, PJVAL jvp, int i); void InitArray(PGLOBAL g); protected: diff --git a/storage/connect/mysql-test/connect/r/bson_mongo_c.result b/storage/connect/mysql-test/connect/r/bson_mongo_c.result index 83bf7cd1974..e2273be4bec 100644 --- a/storage/connect/mysql-test/connect/r/bson_mongo_c.result +++ b/storage/connect/mysql-test/connect/r/bson_mongo_c.result @@ -363,7 +363,7 @@ _id item prices_0 prices_1 prices_2 prices_3 prices_4 1 journal 87 45 63 12 78 2 notebook 123 456 789 NULL NULL 3 paper 5 7 3 8 NULL -4 planner 25 71 44 27 NULL +4 planner 25 71 NULL 44 27 5 postcard 5 7 3 8 NULL DROP TABLE t1; # diff --git a/storage/connect/mysql-test/connect/r/json_mongo_c.result b/storage/connect/mysql-test/connect/r/json_mongo_c.result index 482ccc85b57..6d4957167fc 100644 --- a/storage/connect/mysql-test/connect/r/json_mongo_c.result +++ b/storage/connect/mysql-test/connect/r/json_mongo_c.result @@ -363,7 +363,7 @@ _id item prices_0 prices_1 prices_2 prices_3 prices_4 1 journal 87 45 63 12 78 2 notebook 123 456 789 NULL NULL 3 paper 5 7 3 8 NULL -4 planner 25 71 44 27 NULL +4 planner 25 71 NULL 44 27 5 postcard 5 7 3 8 NULL DROP TABLE t1; # diff --git a/storage/connect/mysql-test/connect/r/mongo_c.result b/storage/connect/mysql-test/connect/r/mongo_c.result index 8b86ce32943..899a123dc5f 100644 --- a/storage/connect/mysql-test/connect/r/mongo_c.result +++ b/storage/connect/mysql-test/connect/r/mongo_c.result @@ -64,23 +64,23 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `_id` char(24) NOT NULL, - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` varchar(512) NOT NULL `FIELD_FORMAT`='address.coord', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` varchar(512) NOT NULL `JPATH`='address.coord', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, `cuisine` char(64) NOT NULL, - `grades_0` varchar(512) DEFAULT NULL `FIELD_FORMAT`='grades.0', + `grades_0` varchar(512) DEFAULT NULL `JPATH`='grades.0', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=C,Version=0' `DATA_CHARSET`='utf8' SELECT * FROM t1 LIMIT 5; _id address_building address_coord address_street address_zipcode borough cuisine grades_0 name restaurant_id -58ada47de5a51ddfcd5ed51c 1007 Morris Park Ave 10462 Bronx Bakery {"date":{"$date":1393804800000},"grade":"A","score":2} Morris Park Bake Shop 30075445 -58ada47de5a51ddfcd5ed51d 469 Flatbush Avenue 11225 Brooklyn Hamburgers {"date":{"$date":1419897600000},"grade":"A","score":8} Wendy'S 30112340 -58ada47de5a51ddfcd5ed51e 351 West 57 Street 10019 Manhattan Irish {"date":{"$date":1409961600000},"grade":"A","score":2} Dj Reynolds Pub And Restaurant 30191841 -58ada47de5a51ddfcd5ed51f 2780 Stillwell Avenue 11224 Brooklyn American {"date":{"$date":1402358400000},"grade":"A","score":5} Riviera Caterer 40356018 -58ada47de5a51ddfcd5ed520 97-22 63 Road 11374 Queens Jewish/Kosher {"date":{"$date":1416787200000},"grade":"Z","score":20} Tov Kosher Kitchen 40356068 +58ada47de5a51ddfcd5ed51c 1007 [-73.856076999999999089,40.848447000000000173] Morris Park Ave 10462 Bronx Bakery {"date":{"$date":1393804800000},"grade":"A","score":2} Morris Park Bake Shop 30075445 +58ada47de5a51ddfcd5ed51d 469 [-73.96170399999999745,40.66294200000000103] Flatbush Avenue 11225 Brooklyn Hamburgers {"date":{"$date":1419897600000},"grade":"A","score":8} Wendy'S 30112340 +58ada47de5a51ddfcd5ed51e 351 [-73.985135599999992451,40.767691900000002647] West 57 Street 10019 Manhattan Irish {"date":{"$date":1409961600000},"grade":"A","score":2} Dj Reynolds Pub And Restaurant 30191841 +58ada47de5a51ddfcd5ed51f 2780 [-73.982419999999990523,40.579504999999997494] Stillwell Avenue 11224 Brooklyn American {"date":{"$date":1402358400000},"grade":"A","score":5} Riviera Caterer 40356018 +58ada47de5a51ddfcd5ed520 97-22 [-73.860115199999995639,40.731173900000001709] 63 Road 11374 Queens Jewish/Kosher {"date":{"$date":1416787200000},"grade":"Z","score":20} Tov Kosher Kitchen 40356068 DROP TABLE t1; # # Dropping a column @@ -249,14 +249,14 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `_id` char(24) NOT NULL, - `address_building` char(6) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord_0` double(12,6) NOT NULL `FIELD_FORMAT`='address.coord.0', - `address_street` char(25) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `address_building` char(6) NOT NULL `JPATH`='address.building', + `address_coord_0` double(12,6) NOT NULL `JPATH`='address.coord.0', + `address_street` char(25) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, - `grades_0_date` datetime NOT NULL `FIELD_FORMAT`='grades.0.date', - `grades_0_grade` char(14) NOT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_0_score` int(11) NOT NULL `FIELD_FORMAT`='grades.0.score', + `grades_0_date` datetime NOT NULL `JPATH`='grades.0.date', + `grades_0_grade` char(14) NOT NULL `JPATH`='grades.0.grade', + `grades_0_score` int(11) NOT NULL `JPATH`='grades.0.score', `name` char(32) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `COLIST`='{"projection":{"cuisine":0}}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=C,level=2,version=0' diff --git a/storage/connect/mysql-test/connect/r/mongo_java_2.result b/storage/connect/mysql-test/connect/r/mongo_java_2.result index cccda2760d6..bcedd717cc4 100644 --- a/storage/connect/mysql-test/connect/r/mongo_java_2.result +++ b/storage/connect/mysql-test/connect/r/mongo_java_2.result @@ -64,13 +64,13 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `_id` char(24) NOT NULL, - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` char(41) NOT NULL `FIELD_FORMAT`='address.coord', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` char(41) NOT NULL `JPATH`='address.coord', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, `cuisine` char(64) NOT NULL, - `grades_0` char(99) DEFAULT NULL `FIELD_FORMAT`='grades.0', + `grades_0` char(99) DEFAULT NULL `JPATH`='grades.0', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=Java,Version=2' `DATA_CHARSET`='utf8' @@ -249,14 +249,14 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `_id` char(24) NOT NULL, - `address_building` char(6) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord_0` double(18,14) NOT NULL `FIELD_FORMAT`='address.coord.0', - `address_street` char(25) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `address_building` char(6) NOT NULL `JPATH`='address.building', + `address_coord_0` double(18,14) NOT NULL `JPATH`='address.coord.0', + `address_street` char(25) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, - `grades_0_date` datetime NOT NULL `FIELD_FORMAT`='grades.0.date', - `grades_0_grade` char(14) NOT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_0_score` int(2) NOT NULL `FIELD_FORMAT`='grades.0.score', + `grades_0_date` datetime NOT NULL `JPATH`='grades.0.date', + `grades_0_grade` char(14) NOT NULL `JPATH`='grades.0.grade', + `grades_0_score` int(2) NOT NULL `JPATH`='grades.0.score', `name` char(32) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=2' diff --git a/storage/connect/mysql-test/connect/r/mongo_java_3.result b/storage/connect/mysql-test/connect/r/mongo_java_3.result index ae39148a156..3183d4984d6 100644 --- a/storage/connect/mysql-test/connect/r/mongo_java_3.result +++ b/storage/connect/mysql-test/connect/r/mongo_java_3.result @@ -64,13 +64,13 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `_id` char(24) NOT NULL, - `address_building` char(10) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord` char(39) NOT NULL `FIELD_FORMAT`='address.coord', - `address_street` char(38) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `address_building` char(10) NOT NULL `JPATH`='address.building', + `address_coord` char(39) NOT NULL `JPATH`='address.coord', + `address_street` char(38) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, `cuisine` char(64) NOT NULL, - `grades_0` char(84) DEFAULT NULL `FIELD_FORMAT`='grades.0', + `grades_0` char(84) DEFAULT NULL `JPATH`='grades.0', `name` char(98) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `OPTION_LIST`='Depth=1,Driver=Java,Version=3' `DATA_CHARSET`='utf8' @@ -249,14 +249,14 @@ SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `_id` char(24) NOT NULL, - `address_building` char(6) NOT NULL `FIELD_FORMAT`='address.building', - `address_coord_0` double(18,14) NOT NULL `FIELD_FORMAT`='address.coord.0', - `address_street` char(25) NOT NULL `FIELD_FORMAT`='address.street', - `address_zipcode` char(5) NOT NULL `FIELD_FORMAT`='address.zipcode', + `address_building` char(6) NOT NULL `JPATH`='address.building', + `address_coord_0` double(18,14) NOT NULL `JPATH`='address.coord.0', + `address_street` char(25) NOT NULL `JPATH`='address.street', + `address_zipcode` char(5) NOT NULL `JPATH`='address.zipcode', `borough` char(13) NOT NULL, - `grades_0_date` datetime NOT NULL `FIELD_FORMAT`='grades.0.date', - `grades_0_grade` char(14) NOT NULL `FIELD_FORMAT`='grades.0.grade', - `grades_0_score` int(2) NOT NULL `FIELD_FORMAT`='grades.0.score', + `grades_0_date` datetime NOT NULL `JPATH`='grades.0.date', + `grades_0_grade` char(14) NOT NULL `JPATH`='grades.0.grade', + `grades_0_score` int(2) NOT NULL `JPATH`='grades.0.score', `name` char(32) NOT NULL, `restaurant_id` char(8) NOT NULL ) ENGINE=CONNECT DEFAULT CHARSET=latin1 `TABLE_TYPE`='MONGO' `TABNAME`='restaurants' `COLIST`='{"cuisine":0}' `FILTER`='{"cuisine":"French","borough":{"$ne":"Manhattan"}}' `OPTION_LIST`='Driver=Java,level=2,version=3' diff --git a/storage/connect/mysql-test/connect/std_data/Mongo2.jar b/storage/connect/mysql-test/connect/std_data/Mongo2.jar Binary files differindex 9be654bd4c8..ae485805d6a 100644 --- a/storage/connect/mysql-test/connect/std_data/Mongo2.jar +++ b/storage/connect/mysql-test/connect/std_data/Mongo2.jar diff --git a/storage/connect/mysql-test/connect/std_data/Mongo3.jar b/storage/connect/mysql-test/connect/std_data/Mongo3.jar Binary files differindex 2850177a668..91dbc4acbeb 100644 --- a/storage/connect/mysql-test/connect/std_data/Mongo3.jar +++ b/storage/connect/mysql-test/connect/std_data/Mongo3.jar diff --git a/storage/connect/tabbson.cpp b/storage/connect/tabbson.cpp index 8477d22d364..aae9a11b28c 100644 --- a/storage/connect/tabbson.cpp +++ b/storage/connect/tabbson.cpp @@ -1171,7 +1171,7 @@ bool BSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Collname = GetStringCatInfo(g, "Name", (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); Collname = GetStringCatInfo(g, "Tabname", Collname); - Options = GetStringCatInfo(g, "Colist", NULL); + Options = GetStringCatInfo(g, "Colist", Xcol ? "all" : NULL); Filter = GetStringCatInfo(g, "Filter", NULL); Pipe = GetBoolCatInfo("Pipeline", false); Driver = GetStringCatInfo(g, "Driver", NULL); @@ -1215,7 +1215,7 @@ PTDB BSONDEF::GetTable(PGLOBAL g, MODE m) if (Lrecl) { // Allocate the parse work memory - G = PlugInit(NULL, (size_t)Lrecl * (Pretty < 0 ? 2 : 4)); + G = PlugInit(NULL, (size_t)Lrecl * (Pretty < 0 ? 3 : 5)); } else { strcpy(g->Message, "LRECL is not defined"); return NULL; @@ -1249,6 +1249,7 @@ PTDB BSONDEF::GetTable(PGLOBAL g, MODE m) #endif // !MONGO_SUPPORT } // endif Driver + Pretty = 4; // Not a file } else if (Zipped) { #if defined(ZIP_SUPPORT) if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { @@ -1676,6 +1677,7 @@ BSONCOL::BSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) Xpd = false; Parsed = false; Warned = false; + Sgfy = false; } // end of BSONCOL constructor /***********************************************************************/ @@ -1695,6 +1697,7 @@ BSONCOL::BSONCOL(BSONCOL* col1, PTDB tdbp) : DOSCOL(col1, tdbp) Xpd = col1->Xpd; Parsed = col1->Parsed; Warned = col1->Warned; + Sgfy = col1->Sgfy; } // end of BSONCOL copy constructor /***********************************************************************/ @@ -1966,8 +1969,10 @@ PSZ BSONCOL::GetJpath(PGLOBAL g, bool proj) if (*p1 == '$') p1++; if (*p1 == '.') p1++; mgopath = PlugDup(g, p1); - } else + } else { + Sgfy = true; return NULL; + } // endif for (p1 = p2 = mgopath; *p1; p1++) if (i) { // Inside [] @@ -2005,6 +2010,7 @@ PSZ BSONCOL::GetJpath(PGLOBAL g, bool proj) case '*': if (*(p2 - 1) == '.' && !*(p1 + 1)) { p2--; // Suppress last :* + Sgfy = true; break; } // endif p2 @@ -2013,6 +2019,9 @@ PSZ BSONCOL::GetJpath(PGLOBAL g, bool proj) break; } // endswitch p1; + if (*(p2 - 1) == '.') + p2--; + *p2 = 0; return mgopath; } else diff --git a/storage/connect/tabbson.h b/storage/connect/tabbson.h index e9c5cc6477f..7f41bba6bd9 100644 --- a/storage/connect/tabbson.h +++ b/storage/connect/tabbson.h @@ -1,7 +1,7 @@ /*************** tabbson H Declares Source Code File (.H) **************/ -/* Name: tabbson.h Version 1.0 */ +/* Name: tabbson.h Version 1.1 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2020 */ +/* (C) Copyright to the author Olivier BERTRAND 2020 - 2021 */ /* */ /* This file contains the BSON classes declares. */ /***********************************************************************/ @@ -242,7 +242,8 @@ public: BSONCOL(BSONCOL* colp, PTDB tdbp); // Constructor used in copy process // Implementation - virtual int GetAmType(void) { return Tbp->GetAmType(); } + virtual int GetAmType(void) { return Tbp->GetAmType(); } + virtual bool Stringify(void) { return Sgfy; } // Methods virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); @@ -270,6 +271,7 @@ protected: bool Xpd; // True for expandable column bool Parsed; // True when parsed bool Warned; // True when warning issued + bool Sgfy; // True if stringified }; // end of class BSONCOL /* -------------------------- TDBBSON class -------------------------- */ diff --git a/storage/connect/tabcmg.cpp b/storage/connect/tabcmg.cpp index f2ff721627c..1552bdde58a 100644 --- a/storage/connect/tabcmg.cpp +++ b/storage/connect/tabcmg.cpp @@ -1,6 +1,6 @@ /************** tabcmg C++ Program Source Code File (.CPP) *************/ -/* PROGRAM NAME: tabcmg Version 1.1 */ -/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* PROGRAM NAME: tabcmg Version 1.2 */ +/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */ /* This program are the C MongoDB class DB execution routines. */ /***********************************************************************/ @@ -84,69 +84,80 @@ bool CMGDISC::FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc, bcol.Cbn = false; - if (BSON_ITER_HOLDS_UTF8(iter)) { - bcol.Type = TYPE_STRING; - bcol.Len = strlen(bson_iter_utf8(iter, NULL)); - } else if (BSON_ITER_HOLDS_INT32(iter)) { - bcol.Type = TYPE_INT; - bcol.Len = 11; // bson_iter_int32(iter) - } else if (BSON_ITER_HOLDS_INT64(iter)) { - bcol.Type = TYPE_BIGINT; - bcol.Len = 22; // bson_iter_int64(iter) - } else if (BSON_ITER_HOLDS_DOUBLE(iter)) { - bcol.Type = TYPE_DOUBLE; - bcol.Len = 12; - bcol.Scale = 6; // bson_iter_double(iter) - } else if (BSON_ITER_HOLDS_DATE_TIME(iter)) { - bcol.Type = TYPE_DATE; - bcol.Len = 19; // bson_iter_date_time(iter) - } else if (BSON_ITER_HOLDS_BOOL(iter)) { - bcol.Type = TYPE_TINY; - bcol.Len = 1; - } else if (BSON_ITER_HOLDS_OID(iter)) { - bcol.Type = TYPE_STRING; - bcol.Len = 24; // bson_iter_oid(iter) - } else if (BSON_ITER_HOLDS_DECIMAL128(iter)) { - bcol.Type = TYPE_DECIM; - bcol.Len = 32; // bson_iter_decimal128(iter, &dec) - } else if (BSON_ITER_HOLDS_DOCUMENT(iter)) { - if (lvl < 0) - continue; - else if (lvl <= k) { + switch (bson_iter_type(iter)) { + case BSON_TYPE_UTF8: bcol.Type = TYPE_STRING; - bcol.Len = 512; - } else { - bson_iter_t child; - - if (bson_iter_recurse(iter, &child)) - if (FindInDoc(g, &child, NULL, colname, fmt, k + 1, false)) - return true; - - newcol = false; - } // endif lvl - - } else if (BSON_ITER_HOLDS_ARRAY(iter)) { - if (lvl < 0) - continue; - else if (lvl <= k) { + bcol.Len = strlen(bson_iter_utf8(iter, NULL)); + break; + case BSON_TYPE_INT32: + bcol.Type = TYPE_INT; + bcol.Len = 11; // bson_iter_int32(iter) + break; + case BSON_TYPE_INT64: + bcol.Type = TYPE_BIGINT; + bcol.Len = 22; // bson_iter_int64(iter) + break; + case BSON_TYPE_DOUBLE: + bcol.Type = TYPE_DOUBLE; + bcol.Len = 12; + bcol.Scale = 6; // bson_iter_double(iter) + break; + case BSON_TYPE_DATE_TIME: + bcol.Type = TYPE_DATE; + bcol.Len = 19; // bson_iter_date_time(iter) + break; + case BSON_TYPE_BOOL: + bcol.Type = TYPE_TINY; + bcol.Len = 1; + break; + case BSON_TYPE_OID: bcol.Type = TYPE_STRING; - bcol.Len = 512; - } else { - bson_t *arr; - bson_iter_t itar; - const uint8_t *data = NULL; - uint32_t len = 0; - - bson_iter_array(iter, &len, &data); - arr = bson_new_from_data(data, len); - - if (FindInDoc(g, &itar, arr, colname, fmt, k + 1, !all)) - return true; + bcol.Len = 24; // bson_iter_oid(iter) + break; + case BSON_TYPE_DECIMAL128: + bcol.Type = TYPE_DECIM; + bcol.Len = 32; // bson_iter_decimal128(iter, &dec) + break; + case BSON_TYPE_DOCUMENT: + if (lvl < 0) + continue; + else if (lvl <= k) { + bcol.Type = TYPE_STRING; + bcol.Len = 512; + } else { + bson_iter_t child; + + if (bson_iter_recurse(iter, &child)) + if (FindInDoc(g, &child, NULL, colname, fmt, k + 1, false)) + return true; + + newcol = false; + } // endif lvl + + break; + case BSON_TYPE_ARRAY: + if (lvl < 0) + continue; + else if (lvl <= k) { + bcol.Type = TYPE_STRING; + bcol.Len = 512; + } else { + bson_t* arr; + bson_iter_t itar; + const uint8_t* data = NULL; + uint32_t len = 0; + + bson_iter_array(iter, &len, &data); + arr = bson_new_from_data(data, len); + + if (FindInDoc(g, &itar, arr, colname, fmt, k + 1, !all)) + return true; - newcol = false; - } // endif lvl + newcol = false; + } // endif lvl - } // endif's + break; + } // endswitch iter if (newcol) AddColumn(g, colname, fmt, k); @@ -178,6 +189,7 @@ TDBCMG::TDBCMG(MGODEF *tdp) : TDBEXT(tdp) Pcg.Coll_name = tdp->Tabname; Pcg.Options = tdp->Colist; Pcg.Filter = tdp->Filter; + Pcg.Line = NULL; Pcg.Pipe = tdp->Pipe && tdp->Colist != NULL; B = tdp->Base ? 1 : 0; } else { @@ -186,6 +198,7 @@ TDBCMG::TDBCMG(MGODEF *tdp) : TDBEXT(tdp) Pcg.Coll_name = NULL; Pcg.Options = NULL; Pcg.Filter = NULL; + Pcg.Line = NULL; Pcg.Pipe = false; B = 0; } // endif tdp @@ -381,7 +394,21 @@ MGOCOL::MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) : EXTCOL(cdp, tdbp, cprec, i, "MGO") { Tmgp = (PTDBCMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); - Jpath = cdp->GetFmt() ? cdp->GetFmt() : cdp->GetName(); + Sgfy = false; + + if ((Jpath = cdp->GetFmt())) { + int n = strlen(Jpath) - 1; + + if (Jpath[n] == '*') { + Jpath = PlugDup(g, cdp->GetFmt()); + if (Jpath[n - 1] == '.') n--; + Jpath[n] = 0; + Sgfy = true; + } // endif Jpath + + } else + Jpath = cdp->GetName(); + } // end of MGOCOL constructor /***********************************************************************/ @@ -392,6 +419,7 @@ MGOCOL::MGOCOL(MGOCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp) { Tmgp = col1->Tmgp; Jpath = col1->Jpath; + Sgfy = col1->Sgfy; } // end of MGOCOL copy constructor /***********************************************************************/ @@ -419,6 +447,9 @@ PSZ MGOCOL::GetJpath(PGLOBAL g, bool proj) } else *p2++ = *p1; + if (*(p2 - 1) == '.') + p2--; + *p2 = 0; return projpath; } else diff --git a/storage/connect/tabcmg.h b/storage/connect/tabcmg.h index 260f2def8a2..44448590da1 100644 --- a/storage/connect/tabcmg.h +++ b/storage/connect/tabcmg.h @@ -1,7 +1,7 @@ /**************** tabcmg H Declares Source Code File (.H) **************/ -/* Name: tabcmg.h Version 1.2 */ +/* Name: tabcmg.h Version 1.3 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */ /* */ /* This file contains the MongoDB classes declares. */ /***********************************************************************/ @@ -96,6 +96,7 @@ public: // Implementation virtual int GetAmType(void) { return Tmgp->GetAmType(); } + virtual bool Stringify(void) { return Sgfy; } // Methods virtual PSZ GetJpath(PGLOBAL g, bool proj); @@ -109,6 +110,7 @@ protected: // Members TDBCMG *Tmgp; // To the MGO table block char *Jpath; // The json path + bool Sgfy; // True if stringified }; // end of class MGOCOL /***********************************************************************/ diff --git a/storage/connect/tabjmg.cpp b/storage/connect/tabjmg.cpp index 850d9e5fa9b..300091f78ad 100644 --- a/storage/connect/tabjmg.cpp +++ b/storage/connect/tabjmg.cpp @@ -384,7 +384,7 @@ int TDBJMG::WriteDB(PGLOBAL g) int rc = RC_OK; if (Mode == MODE_INSERT) { - rc = Jcp->DocWrite(g); + rc = Jcp->DocWrite(g, NULL); } else if (Mode == MODE_DELETE) { rc = Jcp->DocDelete(g, false); } else if (Mode == MODE_UPDATE) { @@ -420,8 +420,21 @@ JMGCOL::JMGCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) : EXTCOL(cdp, tdbp, cprec, i, "MGO") { Tmgp = (PTDBJMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); - Jpath = cdp->GetFmt() ? cdp->GetFmt() : cdp->GetName(); -//Mbuf = NULL; + Sgfy = false; + + if ((Jpath = cdp->GetFmt())) { + int n = strlen(Jpath) - 1; + + if (Jpath[n] == '*') { + Jpath = PlugDup(g, cdp->GetFmt()); + if (Jpath[n - 1] == '.') n--; + Jpath[n] = 0; + Sgfy = true; + } // endif Jpath + + } else + Jpath = cdp->GetName(); + } // end of JMGCOL constructor /***********************************************************************/ @@ -432,7 +445,7 @@ JMGCOL::JMGCOL(JMGCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp) { Tmgp = col1->Tmgp; Jpath = col1->Jpath; -//Mbuf = col1->Mbuf; + Sgfy = col1->Sgfy; } // end of JMGCOL copy constructor /***********************************************************************/ @@ -442,7 +455,7 @@ PSZ JMGCOL::GetJpath(PGLOBAL g, bool proj) { if (Jpath) { if (proj) { - char *p1, *p2, *projpath = PlugDup(g, Jpath); + char* p1, * p2, * projpath = PlugDup(g, Jpath); int i = 0; for (p1 = p2 = projpath; *p1; p1++) @@ -460,6 +473,9 @@ PSZ JMGCOL::GetJpath(PGLOBAL g, bool proj) } else *p2++ = *p1; + if (*(p2 - 1) == '.') + p2--; + *p2 = 0; return projpath; } else diff --git a/storage/connect/tabjmg.h b/storage/connect/tabjmg.h index 5a637145cff..e8f08730b89 100644 --- a/storage/connect/tabjmg.h +++ b/storage/connect/tabjmg.h @@ -1,7 +1,7 @@ /**************** tabjmg H Declares Source Code File (.H) **************/ -/* Name: tabjmg.h Version 1.1 */ +/* Name: tabjmg.h Version 1.2 */ /* */ -/* (C) Copyright to the author Olivier BERTRAND 2017 */ +/* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */ /* */ /* This file contains the MongoDB classes using the Java Driver. */ /***********************************************************************/ @@ -106,6 +106,7 @@ public: // Implementation virtual int GetAmType(void) {return Tmgp->GetAmType();} + virtual bool Stringify(void) { return Sgfy; } // Methods //virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); @@ -123,7 +124,7 @@ protected: // Members TDBJMG *Tmgp; // To the MGO table block char *Jpath; // The json path -//char *Mbuf; // The Mini buffer + bool Sgfy; // True if stringified }; // end of class JMGCOL /***********************************************************************/ diff --git a/storage/connect/tabjson.cpp b/storage/connect/tabjson.cpp index dee4b737a89..dfcf3ee2d4f 100644 --- a/storage/connect/tabjson.cpp +++ b/storage/connect/tabjson.cpp @@ -178,7 +178,7 @@ int JSONDISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ dsn, PTOS topt) lvl = GetIntegerTableOption(g, topt, "Depth", lvl); sep = GetStringTableOption(g, topt, "Separator", "."); strfy = GetStringTableOption(g, topt, "Stringify", NULL); - sz = GetIntegerTableOption(g, topt, "Jsize", 250); + sz = GetIntegerTableOption(g, topt, "Jsize", 1024); limit = GetIntegerTableOption(g, topt, "Limit", 10); /*********************************************************************/ @@ -647,7 +647,7 @@ bool JSONDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) Collname = GetStringCatInfo(g, "Name", (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name); Collname = GetStringCatInfo(g, "Tabname", Collname); - Options = GetStringCatInfo(g, "Colist", NULL); + Options = GetStringCatInfo(g, "Colist", Xcol ? "all" : NULL); Filter = GetStringCatInfo(g, "Filter", NULL); Pipe = GetBoolCatInfo("Pipeline", false); Driver = GetStringCatInfo(g, "Driver", NULL); @@ -716,6 +716,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) #endif // !MONGO_SUPPORT } // endif Driver + Pretty = 4; // Not a file } else if (Zipped) { #if defined(ZIP_SUPPORT) if (m == MODE_READ || m == MODE_ANY || m == MODE_ALTER) { @@ -761,7 +762,7 @@ PTDB JSONDEF::GetTable(PGLOBAL g, MODE m) G->jump_level = 0; ((TDBJSN*)tdbp)->G = G; #endif // 0 - ((TDBJSN*)tdbp)->G = PlugInit(NULL, (size_t)Lrecl * (Pretty >= 0 ? 10 : 2)); + ((TDBJSN*)tdbp)->G = PlugInit(NULL, (size_t)Lrecl * (Pretty >= 0 ? 12 : 4)); } else { strcpy(g->Message, "LRECL is not defined"); return NULL; @@ -1277,6 +1278,7 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) Xpd = false; Parsed = false; Warned = false; + Sgfy = false; } // end of JSONCOL constructor /***********************************************************************/ @@ -1296,6 +1298,7 @@ JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp) Xpd = col1->Xpd; Parsed = col1->Parsed; Warned = col1->Warned; + Sgfy = col1->Sgfy; } // end of JSONCOL copy constructor /***********************************************************************/ @@ -1568,8 +1571,10 @@ PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj) if (*p1 == '$') p1++; if (*p1 == '.') p1++; mgopath = PlugDup(g, p1); - } else + } else { + Sgfy = true; return NULL; + } // endif for (p1 = p2 = mgopath; *p1; p1++) if (i) { // Inside [] @@ -1607,6 +1612,7 @@ PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj) case '*': if (*(p2 - 1) == '.' && !*(p1 + 1)) { p2--; // Suppress last :* + Sgfy = true; break; } // endif p2 @@ -1615,6 +1621,9 @@ PSZ JSONCOL::GetJpath(PGLOBAL g, bool proj) break; } // endswitch p1; + if (*(p2 - 1) == '.') + p2--; + *p2 = 0; return mgopath; } else @@ -2127,10 +2136,14 @@ void JSONCOL::WriteColumn(PGLOBAL g) 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 (s && *s) { + if (!(jsp = ParseJson(G, s, strlen(s)))) { + strcpy(g->Message, s); + throw 666; + } // endif jsp + + } else + jsp = NULL; if (arp) { if (Nod > 1 && Nodes[Nod-2].Op == OP_EQ) @@ -2560,8 +2573,8 @@ int TDBJSON::WriteDB(PGLOBAL g) if (Mode == MODE_INSERT) { Doc->AddArrayValue(g, vp); Row = new(g) JOBJECT; - } else if (Doc->SetArrayValue(g, vp, Fpos)) - return RC_FX; + } else + Doc->SetArrayValue(g, vp, Fpos); } else if (Jmode == MODE_ARRAY) { PJVAL vp = new(g) JVALUE(Row); @@ -2569,15 +2582,15 @@ int TDBJSON::WriteDB(PGLOBAL g) if (Mode == MODE_INSERT) { Doc->AddArrayValue(g, vp); Row = new(g) JARRAY; - } else if (Doc->SetArrayValue(g, vp, Fpos)) - return RC_FX; + } else + Doc->SetArrayValue(g, vp, Fpos); } else { // if (Jmode == MODE_VALUE) if (Mode == MODE_INSERT) { Doc->AddArrayValue(g, (PJVAL)Row); Row = new(g) JVALUE; - } else if (Doc->SetArrayValue(g, (PJVAL)Row, Fpos)) - return RC_FX; + } else + Doc->SetArrayValue(g, (PJVAL)Row, Fpos); } // endif Jmode diff --git a/storage/connect/tabjson.h b/storage/connect/tabjson.h index 1062928d410..523015c66b2 100644 --- a/storage/connect/tabjson.h +++ b/storage/connect/tabjson.h @@ -216,7 +216,8 @@ public: JSONCOL(JSONCOL *colp, PTDB tdbp); // Constructor used in copy process // Implementation - virtual int GetAmType(void) {return Tjp->GetAmType();} + virtual int GetAmType(void) {return Tjp->GetAmType();} + virtual bool Stringify(void) { return Sgfy; } // Methods virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); @@ -251,6 +252,7 @@ public: bool Xpd; // True for expandable column bool Parsed; // True when parsed bool Warned; // True when warning issued + bool Sgfy; // True if stringified }; // end of class JSONCOL /* -------------------------- TDBJSON class -------------------------- */ |