1/************** mongo C++ Program Source Code File (.CPP) **************/
2/* PROGRAM NAME: mongo Version 1.0 */
3/* (C) Copyright to the author Olivier BERTRAND 2017 */
4/* These programs are the MGODEF class execution routines. */
5/***********************************************************************/
6
7/***********************************************************************/
8/* Include relevant sections of the MariaDB header file. */
9/***********************************************************************/
10#include <my_global.h>
11
12/***********************************************************************/
13/* Include application header files: */
14/* global.h is header containing all global declarations. */
15/* plgdbsem.h is header containing the DB application declarations. */
16/***********************************************************************/
17#include "global.h"
18#include "plgdbsem.h"
19#include "xtable.h"
20#include "tabext.h"
21#include "filter.h"
22#if defined(CMGO_SUPPORT)
23#include "tabcmg.h"
24#endif // CMGO_SUPPORT
25#if defined(JAVA_SUPPORT)
26#include "tabjmg.h"
27#endif // JAVA_SUPPORT
28#include "resource.h"
29
30/***********************************************************************/
31/* This should be an option. */
32/***********************************************************************/
33#define MAXCOL 200 /* Default max column nb in result */
34#define TYPE_UNKNOWN 12 /* Must be greater than other types */
35
36bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s);
37bool IsNum(PSZ s);
38
39/***********************************************************************/
40/* Make selector json representation for Mongo tables. */
41/***********************************************************************/
42bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s)
43{
44 OPVAL opc = fp->GetOpc();
45
46 s->Append('{');
47
48 if (opc == OP_AND || opc == OP_OR) {
49 if (fp->GetArgType(0) != TYPE_FILTER || fp->GetArgType(1) != TYPE_FILTER)
50 return true;
51
52 s->Append("\"$");
53 s->Append(opc == OP_AND ? "and" : "or");
54 s->Append("\":[");
55
56 if (MakeSelector(g, (PFIL)fp->Arg(0), s))
57 return true;
58
59 s->Append(',');
60
61 if (MakeSelector(g, (PFIL)fp->Arg(1), s))
62 return true;
63
64 s->Append(']');
65 } else {
66 if (fp->GetArgType(0) != TYPE_COLBLK)
67 return true;
68
69 s->Append('"');
70 s->Append(((PCOL)fp->Arg(0))->GetJpath(g, false));
71 s->Append("\":{\"$");
72
73 switch (opc) {
74 case OP_EQ:
75 s->Append("eq");
76 break;
77 case OP_NE:
78 s->Append("ne");
79 break;
80 case OP_GT:
81 s->Append("gt");
82 break;
83 case OP_GE:
84 s->Append("gte");
85 break;
86 case OP_LT:
87 s->Append("lt");
88 break;
89 case OP_LE:
90 s->Append("lte");
91 break;
92 case OP_NULL:
93 case OP_LIKE:
94 case OP_EXIST:
95 default:
96 return true;
97 } // endswitch Opc
98
99 s->Append("\":");
100
101 if (fp->GetArgType(1) == TYPE_COLBLK) {
102 s->Append("\"$");
103 s->Append(((PEXTCOL)fp->Arg(1))->GetJpath(g, false));
104 s->Append('"');
105 } else {
106 char buf[501];
107
108 fp->Arg(1)->Prints(g, buf, 500);
109 s->Append(buf);
110 } // endif Type
111
112 s->Append('}');
113 } // endif opc
114
115 s->Append('}');
116 return false;
117} // end of MakeSelector
118
119/***********************************************************************/
120/* MGOColumns: construct the result blocks containing the description */
121/* of all the columns of a document contained inside MongoDB. */
122/***********************************************************************/
123PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info)
124{
125 static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
126 TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
127 static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
128 FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
129 unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
130 int ncol = sizeof(buftyp) / sizeof(int);
131 int i, n = 0;
132 PCSZ drv;
133 PBCOL bcp;
134 MGODISC *cmgd = NULL;
135 PQRYRES qrp;
136 PCOLRES crp;
137
138 if (info) {
139 length[0] = 128;
140 length[7] = 256;
141 goto skipit;
142 } // endif info
143
144 /*********************************************************************/
145 /* Open MongoDB. */
146 /*********************************************************************/
147 drv = GetStringTableOption(g, topt, "Driver", NULL);
148
149 if (drv && toupper(*drv) == 'C') {
150#if defined(CMGO_SUPPORT)
151 cmgd = new(g) CMGDISC(g, (int*)length);
152#else
153 sprintf(g->Message, "Mongo %s Driver not available", "C");
154 goto err;
155#endif
156 } else if (drv && toupper(*drv) == 'J') {
157#if defined(JAVA_SUPPORT)
158 cmgd = new(g) JMGDISC(g, (int*)length);
159#else
160 sprintf(g->Message, "Mongo %s Driver not available", "Java");
161 goto err;
162#endif
163 } else { // Driver not specified
164#if defined(CMGO_SUPPORT)
165 cmgd = new(g) CMGDISC(g, (int*)length);
166#else
167 cmgd = new(g) JMGDISC(g, (int*)length);
168#endif
169 } // endif drv
170
171 if ((n = cmgd->GetColumns(g, db, uri, topt)) < 0)
172 goto err;
173
174skipit:
175 if (trace(1))
176 htrc("MGOColumns: n=%d len=%d\n", n, length[0]);
177
178 /*********************************************************************/
179 /* Allocate the structures used to refer to the result set. */
180 /*********************************************************************/
181 qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
182 buftyp, fldtyp, length, false, false);
183
184 crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
185 crp->Name = "Nullable";
186 crp->Next->Name = "Bpath";
187
188 if (info || !qrp)
189 return qrp;
190
191 qrp->Nblin = n;
192
193 /*********************************************************************/
194 /* Now get the results into blocks. */
195 /*********************************************************************/
196 for (i = 0, bcp = cmgd->fbcp; bcp; i++, bcp = bcp->Next) {
197 if (bcp->Type == TYPE_UNKNOWN) // Void column
198 bcp->Type = TYPE_STRING;
199
200 crp = qrp->Colresp; // Column Name
201 crp->Kdata->SetValue(bcp->Name, i);
202 crp = crp->Next; // Data Type
203 crp->Kdata->SetValue(bcp->Type, i);
204 crp = crp->Next; // Type Name
205 crp->Kdata->SetValue(GetTypeName(bcp->Type), i);
206 crp = crp->Next; // Precision
207 crp->Kdata->SetValue(bcp->Len, i);
208 crp = crp->Next; // Length
209 crp->Kdata->SetValue(bcp->Len, i);
210 crp = crp->Next; // Scale (precision)
211 crp->Kdata->SetValue(bcp->Scale, i);
212 crp = crp->Next; // Nullable
213 crp->Kdata->SetValue(bcp->Cbn ? 1 : 0, i);
214 crp = crp->Next; // Field format
215
216 if (crp->Kdata)
217 crp->Kdata->SetValue(bcp->Fmt, i);
218
219 } // endfor i
220
221 /*********************************************************************/
222 /* Return the result pointer. */
223 /*********************************************************************/
224 return qrp;
225
226err:
227 if (cmgd && cmgd->tmgp)
228 cmgd->tmgp->CloseDB(g);
229
230 return NULL;
231} // end of MGOColumns
232
233/***********************************************************************/
234/* Class used to get the columns of a mongo collection. */
235/***********************************************************************/
236MGODISC::MGODISC(PGLOBAL g, int *lg) {
237 length = lg;
238 fbcp = NULL;
239 pbcp = NULL;
240 tmgp = NULL;
241 drv = NULL;
242 i = ncol = lvl = 0;
243 all = false;
244} // end of MGODISC constructor
245
246/***********************************************************************/
247/* Class used to get the columns of a mongo collection. */
248/***********************************************************************/
249int MGODISC::GetColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt)
250{
251 PCSZ level = GetStringTableOption(g, topt, "Level", NULL);
252 PMGODEF tdp;
253
254 if (level) {
255 lvl = atoi(level);
256 lvl = (lvl > 16) ? 16 : lvl;
257 } else
258 lvl = 0;
259
260 all = GetBooleanTableOption(g, topt, "Fullarray", false);
261
262 /*********************************************************************/
263 /* Open the MongoDB collection. */
264 /*********************************************************************/
265 tdp = new(g) MGODEF;
266 tdp->Uri = (uri && *uri) ? uri : "mongodb://localhost:27017";
267 tdp->Driver = drv;
268 tdp->Tabname = GetStringTableOption(g, topt, "Name", NULL);
269 tdp->Tabname = GetStringTableOption(g, topt, "Tabname", tdp->Tabname);
270 tdp->Tabschema = GetStringTableOption(g, topt, "Dbname", db);
271 tdp->Base = GetIntegerTableOption(g, topt, "Base", 0) ? 1 : 0;
272 tdp->Colist = GetStringTableOption(g, topt, "Colist", "all");
273 tdp->Filter = GetStringTableOption(g, topt, "Filter", NULL);
274 tdp->Pipe = GetBooleanTableOption(g, topt, "Pipeline", false);
275 tdp->Version = GetIntegerTableOption(g, topt, "Version", 3);
276 tdp->Wrapname = (PSZ)GetStringTableOption(g, topt, "Wrapper",
277 (tdp->Version == 2) ? "Mongo2Interface" : "Mongo3Interface");
278
279 if (trace(1))
280 htrc("Uri %s coll=%s db=%s colist=%s filter=%s lvl=%d\n",
281 tdp->Uri, tdp->Tabname, tdp->Tabschema, tdp->Colist, tdp->Filter, lvl);
282
283 tmgp = tdp->GetTable(g, MODE_READ);
284 tmgp->SetMode(MODE_READ);
285
286 if (tmgp->OpenDB(g))
287 return -1;
288
289 bcol.Next = NULL;
290 bcol.Name = bcol.Fmt = NULL;
291 bcol.Type = TYPE_UNKNOWN;
292 bcol.Len = bcol.Scale = 0;
293 bcol.Found = true;
294 bcol.Cbn = false;
295
296 if (Init(g))
297 return -1;
298
299 /*********************************************************************/
300 /* Analyse the BSON tree and define columns. */
301 /*********************************************************************/
302 for (i = 1; ; i++) {
303 switch (tmgp->ReadDB(g)) {
304 case RC_EF:
305 return ncol;
306 case RC_FX:
307 return -1;
308 default:
309 GetDoc();
310 } // endswitch ReadDB
311
312 if (Find(g))
313 return -1;
314
315 // Missing columns can be null
316 for (bcp = fbcp; bcp; bcp = bcp->Next) {
317 bcp->Cbn |= !bcp->Found;
318 bcp->Found = false;
319 } // endfor bcp
320
321 } // endfor i
322
323 return ncol;
324} // end of GetColumns
325
326/***********************************************************************/
327/* Add a new column in the column list. */
328/***********************************************************************/
329void MGODISC::AddColumn(PGLOBAL g, PCSZ colname, PCSZ fmt, int k)
330{
331 // Check whether this column was already found
332 for (bcp = fbcp; bcp; bcp = bcp->Next)
333 if (!strcmp(colname, bcp->Name))
334 break;
335
336 if (bcp) {
337 if (bcp->Type != bcol.Type)
338 bcp->Type = TYPE_STRING;
339
340 if (k && *fmt && (!bcp->Fmt || strlen(bcp->Fmt) < strlen(fmt))) {
341 bcp->Fmt = PlugDup(g, fmt);
342 length[7] = MY_MAX(length[7], (signed)strlen(fmt));
343 } // endif *fmt
344
345 bcp->Len = MY_MAX(bcp->Len, bcol.Len);
346 bcp->Scale = MY_MAX(bcp->Scale, bcol.Scale);
347 bcp->Cbn |= bcol.Cbn;
348 bcp->Found = true;
349 } else {
350 // New column
351 bcp = (PBCOL)PlugSubAlloc(g, NULL, sizeof(BCOL));
352 *bcp = bcol;
353 bcp->Cbn |= (i > 1);
354 bcp->Name = PlugDup(g, colname);
355 length[0] = MY_MAX(length[0], (signed)strlen(colname));
356
357 if (k) {
358 bcp->Fmt = PlugDup(g, fmt);
359 length[7] = MY_MAX(length[7], (signed)strlen(fmt));
360 } else
361 bcp->Fmt = NULL;
362
363 if (pbcp) {
364 bcp->Next = pbcp->Next;
365 pbcp->Next = bcp;
366 } else
367 fbcp = bcp;
368
369 ncol++;
370 } // endif jcp
371
372 pbcp = bcp;
373} // end of AddColumn
374
375/* -------------------------- Class MGODEF --------------------------- */
376
377MGODEF::MGODEF(void)
378{
379 Driver = NULL;
380 Uri = NULL;
381 Colist = NULL;
382 Filter = NULL;
383 Level = 0;
384 Base = 0;
385 Version = 0;
386 Pipe = false;
387} // end of MGODEF constructor
388
389/***********************************************************************/
390/* DefineAM: define specific AM block values. */
391/***********************************************************************/
392bool MGODEF::DefineAM(PGLOBAL g, LPCSTR, int poff)
393{
394 if (EXTDEF::DefineAM(g, "MGO", poff))
395 return true;
396 else if (!Tabschema)
397 Tabschema = GetStringCatInfo(g, "Dbname", "*");
398
399 Driver = GetStringCatInfo(g, "Driver", NULL);
400 Uri = GetStringCatInfo(g, "Connect", "mongodb://localhost:27017");
401 Colist = GetStringCatInfo(g, "Colist", NULL);
402 Filter = GetStringCatInfo(g, "Filter", NULL);
403 Base = GetIntCatInfo("Base", 0) ? 1 : 0;
404 Version = GetIntCatInfo("Version", 3);
405
406 if (Version == 2)
407 Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo2Interface");
408 else
409 Wrapname = GetStringCatInfo(g, "Wrapper", "Mongo3Interface");
410
411 Pipe = GetBoolCatInfo("Pipeline", false);
412 return false;
413} // end of DefineAM
414
415/***********************************************************************/
416/* GetTable: makes a new Table Description Block. */
417/***********************************************************************/
418PTDB MGODEF::GetTable(PGLOBAL g, MODE m)
419{
420 if (Driver && toupper(*Driver) == 'C') {
421#if defined(CMGO_SUPPORT)
422 if (Catfunc == FNC_COL)
423 return new(g) TDBGOL(this);
424 else
425 return new(g) TDBCMG(this);
426#else
427 sprintf(g->Message, "Mongo %s Driver not available", "C");
428 return NULL;
429#endif
430 } else if (Driver && toupper(*Driver) == 'J') {
431#if defined(JAVA_SUPPORT)
432 if (Catfunc == FNC_COL)
433 return new(g) TDBJGL(this);
434 else
435 return new(g) TDBJMG(this);
436#else
437 sprintf(g->Message, "Mongo %s Driver not available", "Java");
438 return NULL;
439#endif
440 } else { // Driver not specified
441#if defined(CMGO_SUPPORT)
442 if (Catfunc == FNC_COL)
443 return new(g) TDBGOL(this);
444 else
445 return new(g) TDBCMG(this);
446#else
447 if (Catfunc == FNC_COL)
448 return new(g) TDBJGL(this);
449 else
450 return new(g) TDBJMG(this);
451#endif
452 } // endif Driver
453
454} // end of GetTable
455