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