summaryrefslogtreecommitdiffstats
path: root/storage/connect/mongo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/connect/mongo.cpp')
-rw-r--r--storage/connect/mongo.cpp451
1 files changed, 451 insertions, 0 deletions
diff --git a/storage/connect/mongo.cpp b/storage/connect/mongo.cpp
new file mode 100644
index 00000000..9a35dfb3
--- /dev/null
+++ b/storage/connect/mongo.cpp
@@ -0,0 +1,451 @@
+/************** mongo C++ Program Source Code File (.CPP) **************/
+/* PROGRAM NAME: mongo Version 1.1 */
+/* (C) Copyright to the author Olivier BERTRAND 2021 */
+/* These programs are the MGODEF class 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. */
+/***********************************************************************/
+#include "global.h"
+#include "plgdbsem.h"
+#include "xtable.h"
+#include "tabext.h"
+#include "filter.h"
+#if defined(CMGO_SUPPORT)
+#include "tabcmg.h"
+#endif // CMGO_SUPPORT
+#if defined(JAVA_SUPPORT)
+#include "tabjmg.h"
+#endif // JAVA_SUPPORT
+#include "resource.h"
+
+/***********************************************************************/
+/* This should be an option. */
+/***********************************************************************/
+#define MAXCOL 200 /* Default max column nb in result */
+#define TYPE_UNKNOWN 12 /* Must be greater than other types */
+
+bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s);
+bool IsNum(PSZ s);
+int GetDefaultDepth(void);
+bool JsonAllPath(void);
+
+/***********************************************************************/
+/* Make selector json representation for Mongo tables. */
+/***********************************************************************/
+bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s)
+{
+ OPVAL opc = fp->GetOpc();
+
+ s->Append('{');
+
+ if (opc == OP_AND || opc == OP_OR) {
+ if (fp->GetArgType(0) != TYPE_FILTER || fp->GetArgType(1) != TYPE_FILTER)
+ return true;
+
+ s->Append("\"$");
+ s->Append(opc == OP_AND ? "and" : "or");
+ s->Append("\":[");
+
+ if (MakeSelector(g, (PFIL)fp->Arg(0), s))
+ return true;
+
+ s->Append(',');
+
+ if (MakeSelector(g, (PFIL)fp->Arg(1), s))
+ return true;
+
+ s->Append(']');
+ } else {
+ if (fp->GetArgType(0) != TYPE_COLBLK)
+ return true;
+
+ s->Append('"');
+ s->Append(((PCOL)fp->Arg(0))->GetJpath(g, false));
+ s->Append("\":{\"$");
+
+ switch (opc) {
+ case OP_EQ:
+ s->Append("eq");
+ break;
+ case OP_NE:
+ s->Append("ne");
+ break;
+ case OP_GT:
+ s->Append("gt");
+ break;
+ case OP_GE:
+ s->Append("gte");
+ break;
+ case OP_LT:
+ s->Append("lt");
+ break;
+ case OP_LE:
+ s->Append("lte");
+ break;
+ case OP_NULL:
+ case OP_LIKE:
+ case OP_EXIST:
+ default:
+ return true;
+ } // endswitch Opc
+
+ s->Append("\":");
+
+ if (fp->GetArgType(1) == TYPE_COLBLK) {
+ s->Append("\"$");
+ s->Append(((PEXTCOL)fp->Arg(1))->GetJpath(g, false));
+ s->Append('"');
+ } else {
+ char buf[501];
+
+ fp->Arg(1)->Prints(g, buf, 500);
+ s->Append(buf);
+ } // endif Type
+
+ s->Append('}');
+ } // endif opc
+
+ s->Append('}');
+ return false;
+} // end of MakeSelector
+
+/***********************************************************************/
+/* MGOColumns: construct the result blocks containing the description */
+/* of all the columns of a document contained inside MongoDB. */
+/***********************************************************************/
+PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, 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};
+ unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
+ int ncol = sizeof(buftyp) / sizeof(int);
+ int i, n = 0;
+ PCSZ drv;
+ PBCOL bcp;
+ MGODISC *cmgd = NULL;
+ PQRYRES qrp;
+ PCOLRES crp;
+
+ if (info) {
+ length[0] = 128;
+ length[7] = 256;
+ goto skipit;
+ } // endif info
+
+ /*********************************************************************/
+ /* Open MongoDB. */
+ /*********************************************************************/
+ drv = GetStringTableOption(g, topt, "Driver", NULL);
+
+ if (drv && toupper(*drv) == 'C') {
+#if defined(CMGO_SUPPORT)
+ cmgd = new(g) CMGDISC(g, (int*)length);
+#else
+ snprintf(g->Message, sizeof(g->Message), "Mongo %s Driver not available", "C");
+ goto err;
+#endif
+ } else if (drv && toupper(*drv) == 'J') {
+#if defined(JAVA_SUPPORT)
+ cmgd = new(g) JMGDISC(g, (int*)length);
+#else
+ snprintf(g->Message, sizeof(g->Message), "Mongo %s Driver not available", "Java");
+ goto err;
+#endif
+ } else { // Driver not specified
+#if defined(CMGO_SUPPORT)
+ cmgd = new(g) CMGDISC(g, (int*)length);
+#else
+ cmgd = new(g) JMGDISC(g, (int*)length);
+#endif
+ } // endif drv
+
+ if ((n = cmgd->GetColumns(g, db, uri, topt)) < 0)
+ goto err;
+
+skipit:
+ if (trace(1))
+ htrc("MGOColumns: 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 = "Nullable";
+ crp->Next->Name = "Bpath";
+
+ if (info || !qrp)
+ return qrp;
+
+ qrp->Nblin = n;
+
+ /*********************************************************************/
+ /* Now get the results into blocks. */
+ /*********************************************************************/
+ for (i = 0, bcp = cmgd->fbcp; bcp; i++, bcp = bcp->Next) {
+ if (bcp->Type == TYPE_UNKNOWN) // Void column
+ bcp->Type = TYPE_STRING;
+
+ crp = qrp->Colresp; // Column Name
+ crp->Kdata->SetValue(bcp->Name, i);
+ crp = crp->Next; // Data Type
+ crp->Kdata->SetValue(bcp->Type, i);
+ crp = crp->Next; // Type Name
+ crp->Kdata->SetValue(GetTypeName(bcp->Type), i);
+ crp = crp->Next; // Precision
+ crp->Kdata->SetValue(bcp->Len, i);
+ crp = crp->Next; // Length
+ crp->Kdata->SetValue(bcp->Len, i);
+ crp = crp->Next; // Scale (precision)
+ crp->Kdata->SetValue(bcp->Scale, i);
+ crp = crp->Next; // Nullable
+ crp->Kdata->SetValue(bcp->Cbn ? 1 : 0, i);
+ crp = crp->Next; // Field format
+
+ if (crp->Kdata)
+ crp->Kdata->SetValue(bcp->Fmt, i);
+
+ } // endfor i
+
+ /*********************************************************************/
+ /* Return the result pointer. */
+ /*********************************************************************/
+ return qrp;
+
+err:
+ if (cmgd && cmgd->tmgp)
+ cmgd->tmgp->CloseDB(g);
+
+ return NULL;
+} // end of MGOColumns
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+MGODISC::MGODISC(PGLOBAL g, int *lg) {
+ length = lg;
+ fbcp = NULL;
+ pbcp = NULL;
+ tmgp = NULL;
+ drv = NULL;
+ i = ncol = lvl = 0;
+ all = false;
+} // end of MGODISC constructor
+
+/***********************************************************************/
+/* Class used to get the columns of a mongo collection. */
+/***********************************************************************/
+int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt)
+{
+ PMGODEF tdp;
+
+ lvl = GetIntegerTableOption(g, topt, "Level", GetDefaultDepth());
+ lvl = GetIntegerTableOption(g, topt, "Depth", lvl);
+ all = GetBooleanTableOption(g, topt, "Fullarray", false);
+
+ /*********************************************************************/
+ /* Open the MongoDB collection. */
+ /*********************************************************************/
+ tdp = new(g) MGODEF;
+ tdp->Uri = (uri && *uri) ? uri : "mongodb://localhost:27017";
+ tdp->Driver = drv;
+ tdp->Tabname = GetStringTableOption(g, topt, "Name", NULL);
+ tdp->Tabname = GetStringTableOption(g, topt, "Tabname", tdp->Tabname);
+ tdp->Tabschema = GetStringTableOption(g, topt, "Dbname", db);
+ tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0;
+ tdp->Colist = GetStringTableOption(g, topt, "Colist", "all");
+ tdp->Filter = GetStringTableOption(g, topt, "Filter", NULL);
+ tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false);
+ tdp->Version = GetIntegerTableOption(g, topt, "Version", 3);
+ tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper",
+ (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface");
+
+ if (trace(1))
+ htrc("Uri %s coll=%s db=%s colist=%s filter=%s lvl=%d\n",
+ tdp->Uri, tdp->Tabname, tdp->Tabschema, tdp->Colist, tdp->Filter, lvl);
+
+ tmgp = tdp->GetTable(g, MODE_READ);
+ tmgp->SetMode(MODE_READ);
+
+ if (tmgp->OpenDB(g))
+ return -1;
+
+ bcol.Next = NULL;
+ bcol.Name = bcol.Fmt = NULL;
+ bcol.Type = TYPE_UNKNOWN;
+ bcol.Len = bcol.Scale = 0;
+ bcol.Found = true;
+ bcol.Cbn = false;
+
+ if (Init(g))
+ return -1;
+
+ /*********************************************************************/
+ /* Analyse the BSON tree and define columns. */
+ /*********************************************************************/
+ for (i = 1; ; i++) {
+ switch (tmgp->ReadDB(g)) {
+ case RC_EF:
+ return ncol;
+ case RC_FX:
+ return -1;
+ default:
+ GetDoc();
+ } // endswitch ReadDB
+
+ if (Find(g))
+ return -1;
+
+ // Missing columns can be null
+ for (bcp = fbcp; bcp; bcp = bcp->Next) {
+ bcp->Cbn |= !bcp->Found;
+ bcp->Found = false;
+ } // endfor bcp
+
+ } // endfor i
+
+ return ncol;
+} // end of GetColumns
+
+/***********************************************************************/
+/* Add a new column in the column list. */
+/***********************************************************************/
+void MGODISC::AddColumn(PGLOBAL g, PCSZ colname, PCSZ fmt, int k)
+{
+ // Check whether this column was already found
+ for (bcp = fbcp; bcp; bcp = bcp->Next)
+ if (!strcmp(colname, bcp->Name))
+ break;
+
+ if (bcp) {
+ if (bcp->Type != bcol.Type)
+ bcp->Type = TYPE_STRING;
+
+ if (k && *fmt && (!bcp->Fmt || strlen(bcp->Fmt) < strlen(fmt))) {
+ bcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], (signed)strlen(fmt));
+ } // endif *fmt
+
+ bcp->Len = MY_MAX(bcp->Len, bcol.Len);
+ bcp->Scale = MY_MAX(bcp->Scale, bcol.Scale);
+ bcp->Cbn |= bcol.Cbn;
+ bcp->Found = true;
+ } else {
+ // New column
+ bcp = (PBCOL)PlugSubAlloc(g, NULL, sizeof(BCOL));
+ *bcp = bcol;
+ bcp->Cbn |= (i > 1);
+ bcp->Name = PlugDup(g, colname);
+ length[0] = MY_MAX(length[0], (signed)strlen(colname));
+
+ if (k || JsonAllPath()) {
+ bcp->Fmt = PlugDup(g, fmt);
+ length[7] = MY_MAX(length[7], (signed)strlen(fmt));
+ } else
+ bcp->Fmt = NULL;
+
+ if (pbcp) {
+ bcp->Next = pbcp->Next;
+ pbcp->Next = bcp;
+ } else
+ fbcp = bcp;
+
+ ncol++;
+ } // endif jcp
+
+ pbcp = bcp;
+} // end of AddColumn
+
+/* -------------------------- Class MGODEF --------------------------- */
+
+MGODEF::MGODEF(void)
+{
+ Driver = NULL;
+ Uri = NULL;
+ Colist = NULL;
+ Filter = NULL;
+ Base = 0;
+ Version = 0;
+ Pipe = false;
+} // end of MGODEF constructor
+
+/***********************************************************************/
+/* DefineAM: define specific AM block values. */
+/***********************************************************************/
+bool MGODEF::DefineAM(PGLOBAL g, LPCSTR, int poff)
+{
+ if (EXTDEF::DefineAM(g, "MGO", poff))
+ return true;
+ else if (!Tabschema)
+ Tabschema = GetStringCatInfo(g, "Dbname", "*");
+
+ Driver = GetStringCatInfo(g, "Driver", NULL);
+ Uri = GetStringCatInfo(g, "Connect", "mongodb://localhost:27017");
+ Colist = GetStringCatInfo(g, "Colist", NULL);
+ Filter = GetStringCatInfo(g, "Filter", NULL);
+ Strfy = GetStringCatInfo(g, "Stringify", NULL);
+ Base = GetIntCatInfo("Base", 0) ? 1 : 0;
+ Version = GetIntCatInfo("Version", 3);
+
+ if (Version == 2)
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface");
+ else
+ Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface");
+
+ Pipe = GetBoolCatInfo("Pipeline", false);
+ return false;
+} // end of DefineAM
+
+/***********************************************************************/
+/* GetTable: makes a new Table Description Block. */
+/***********************************************************************/
+PTDB MGODEF::GetTable(PGLOBAL g, MODE m)
+{
+ if (Driver && toupper(*Driver) == 'C') {
+#if defined(CMGO_SUPPORT)
+ if (Catfunc == FNC_COL)
+ return new(g) TDBGOL(this);
+ else
+ return new(g) TDBCMG(this);
+#else
+ snprintf(g->Message, sizeof(g->Message), "Mongo %s Driver not available", "C");
+ return NULL;
+#endif
+ } else if (Driver && toupper(*Driver) == 'J') {
+#if defined(JAVA_SUPPORT)
+ if (Catfunc == FNC_COL)
+ return new(g) TDBJGL(this);
+ else
+ return new(g) TDBJMG(this);
+#else
+ snprintf(g->Message, sizeof(g->Message), "Mongo %s Driver not available", "Java");
+ return NULL;
+#endif
+ } else { // Driver not specified
+#if defined(CMGO_SUPPORT)
+ if (Catfunc == FNC_COL)
+ return new(g) TDBGOL(this);
+ else
+ return new(g) TDBCMG(this);
+#else
+ if (Catfunc == FNC_COL)
+ return new(g) TDBJGL(this);
+ else
+ return new(g) TDBJMG(this);
+#endif
+ } // endif Driver
+
+} // end of GetTable