1 /************** tabcmg C++ Program Source Code File (.CPP) *************/
2 /* PROGRAM NAME: tabcmg Version 1.3 */
3 /* (C) Copyright to the author Olivier BERTRAND 2017 - 2021 */
4 /* This program are the C MongoDB class DB 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 /* tdbdos.h is header containing the TDBDOS declarations. */
17 /* json.h is header containing the JSON classes declarations. */
18 /***********************************************************************/
19 #include "global.h"
20 #include "plgdbsem.h"
21 #include "xtable.h"
22 #include "maputil.h"
23 #include "filamtxt.h"
24 #include "tabext.h"
25 #include "tabcmg.h"
26 #include "tabmul.h"
27 #include "filter.h"
28
29 PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info);
30 bool Stringified(PCSZ, char*);
31
32 /* -------------------------- Class CMGDISC -------------------------- */
33
34 /***********************************************************************/
35 /* Get document. */
36 /***********************************************************************/
GetDoc(void)37 void CMGDISC::GetDoc(void)
38 {
39 doc = ((TDBCMG*)tmgp)->Cmgp->Document;
40 } // end of GetDoc
41
42 /***********************************************************************/
43 /* Analyse passed document. */
44 /***********************************************************************/
45 //bool CMGDISC::Find(PGLOBAL g, int i, int k, bool b)
Find(PGLOBAL g)46 bool CMGDISC::Find(PGLOBAL g)
47 {
48 return FindInDoc(g, &iter, doc, NULL, NULL, 0, false);
49 } // end of Find
50
51 /***********************************************************************/
52 /* Analyse passed document. */
53 /***********************************************************************/
FindInDoc(PGLOBAL g,bson_iter_t * iter,const bson_t * doc,char * pcn,char * pfmt,int k,bool b)54 bool CMGDISC::FindInDoc(PGLOBAL g, bson_iter_t *iter, const bson_t *doc,
55 char *pcn, char *pfmt, int k, bool b)
56 {
57 if (!doc || bson_iter_init(iter, doc)) {
58 const char *key;
59 char colname[65];
60 char fmt[129];
61 bool newcol;
62 size_t n;
63
64 while (bson_iter_next(iter)) {
65 key = bson_iter_key(iter);
66 newcol = true;
67
68 if (pcn) {
69 n = sizeof(colname) - 1;
70 strncpy(colname, pcn, n);
71 colname[n] = 0;
72 n -= strlen(colname);
73 strncat(strncat(colname, "_", n), key, n - 1);
74 } else
75 strcpy(colname, key);
76
77 if (pfmt) {
78 n = sizeof(fmt) - 1;
79 strncpy(fmt, pfmt, n);
80 fmt[n] = 0;
81 n -= strlen(fmt);
82 strncat(strncat(fmt, ".", n), key, n - 1);
83 } else
84 strcpy(fmt, key);
85
86 bcol.Cbn = false;
87
88 switch (bson_iter_type(iter)) {
89 case BSON_TYPE_UTF8:
90 bcol.Type = TYPE_STRING;
91 bcol.Len = strlen(bson_iter_utf8(iter, NULL));
92 break;
93 case BSON_TYPE_INT32:
94 bcol.Type = TYPE_INT;
95 bcol.Len = 11; // bson_iter_int32(iter)
96 break;
97 case BSON_TYPE_INT64:
98 bcol.Type = TYPE_BIGINT;
99 bcol.Len = 22; // bson_iter_int64(iter)
100 break;
101 case BSON_TYPE_DOUBLE:
102 bcol.Type = TYPE_DOUBLE;
103 bcol.Len = 12;
104 bcol.Scale = 6; // bson_iter_double(iter)
105 break;
106 case BSON_TYPE_DATE_TIME:
107 bcol.Type = TYPE_DATE;
108 bcol.Len = 19; // bson_iter_date_time(iter)
109 break;
110 case BSON_TYPE_BOOL:
111 bcol.Type = TYPE_TINY;
112 bcol.Len = 1;
113 break;
114 case BSON_TYPE_OID:
115 bcol.Type = TYPE_STRING;
116 bcol.Len = 24; // bson_iter_oid(iter)
117 break;
118 case BSON_TYPE_DECIMAL128:
119 bcol.Type = TYPE_DECIM;
120 bcol.Len = 32; // bson_iter_decimal128(iter, &dec)
121 break;
122 case BSON_TYPE_DOCUMENT:
123 if (lvl < 0)
124 continue;
125 else if (lvl <= k) {
126 bcol.Type = TYPE_STRING;
127 bcol.Len = 512;
128 } else {
129 bson_iter_t child;
130
131 if (bson_iter_recurse(iter, &child))
132 if (FindInDoc(g, &child, NULL, colname, fmt, k + 1, false))
133 return true;
134
135 newcol = false;
136 } // endif lvl
137
138 break;
139 case BSON_TYPE_ARRAY:
140 if (lvl < 0)
141 continue;
142 else if (lvl <= k) {
143 bcol.Type = TYPE_STRING;
144 bcol.Len = 512;
145 } else {
146 bson_t* arr;
147 bson_iter_t itar;
148 const uint8_t* data = NULL;
149 uint32_t len = 0;
150
151 bson_iter_array(iter, &len, &data);
152 arr = bson_new_from_data(data, len);
153
154 if (FindInDoc(g, &itar, arr, colname, fmt, k + 1, !all))
155 return true;
156
157 newcol = false;
158 } // endif lvl
159
160 break;
161 } // endswitch iter
162
163 if (newcol)
164 AddColumn(g, colname, fmt, k);
165
166 if (b)
167 break; // Test only first element of arrays
168
169 } // endwhile iter
170
171 } // endif doc
172
173 return false;
174 } // end of FindInDoc
175
176 /* --------------------------- Class TDBCMG -------------------------- */
177
178 /***********************************************************************/
179 /* Implementation of the TDBCMG class. */
180 /***********************************************************************/
TDBCMG(MGODEF * tdp)181 TDBCMG::TDBCMG(MGODEF *tdp) : TDBEXT(tdp)
182 {
183 Cmgp = NULL;
184 Cnd = NULL;
185 Pcg.Tdbp = this;
186
187 if (tdp) {
188 Pcg.Uristr = tdp->Uri;
189 Pcg.Db_name = tdp->Tabschema;
190 Pcg.Coll_name = tdp->Tabname;
191 Pcg.Options = tdp->Colist;
192 Pcg.Filter = tdp->Filter;
193 Pcg.Line = NULL;
194 Pcg.Pipe = tdp->Pipe && tdp->Colist != NULL;
195 B = tdp->Base ? 1 : 0;
196 Strfy = tdp->Strfy;
197 } else {
198 Pcg.Uristr = NULL;
199 Pcg.Db_name = NULL;
200 Pcg.Coll_name = NULL;
201 Pcg.Options = NULL;
202 Pcg.Filter = NULL;
203 Pcg.Line = NULL;
204 Pcg.Pipe = false;
205 Strfy = NULL;
206 B = 0;
207 } // endif tdp
208
209 Fpos = -1;
210 N = 0;
211 Done = false;
212 } // end of TDBCMG standard constructor
213
TDBCMG(TDBCMG * tdbp)214 TDBCMG::TDBCMG(TDBCMG *tdbp) : TDBEXT(tdbp)
215 {
216 Cmgp = tdbp->Cmgp;
217 Cnd = tdbp->Cnd;
218 Pcg = tdbp->Pcg;
219 Strfy = tdbp->Strfy;
220 B = tdbp->B;
221 Fpos = tdbp->Fpos;
222 N = tdbp->N;
223 Done = tdbp->Done;
224 } // end of TDBCMG copy constructor
225
226 // Used for update
Clone(PTABS t)227 PTDB TDBCMG::Clone(PTABS t)
228 {
229 PTDB tp;
230 PMGOCOL cp1, cp2;
231 PGLOBAL g = t->G;
232
233 tp = new(g) TDBCMG(this);
234
235 for (cp1 = (PMGOCOL)Columns; cp1; cp1 = (PMGOCOL)cp1->GetNext())
236 if (!cp1->IsSpecial()) {
237 cp2 = new(g) MGOCOL(cp1, tp); // Make a copy
238 NewPointer(t, cp1, cp2);
239 } // endif cp1
240
241 return tp;
242 } // end of Clone
243
244 /***********************************************************************/
245 /* Allocate JSN column description block. */
246 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)247 PCOL TDBCMG::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
248 {
249 PMGOCOL colp = new(g) MGOCOL(g, cdp, this, cprec, n);
250
251 return colp;
252 } // end of MakeCol
253
254 /***********************************************************************/
255 /* InsertSpecialColumn: Put a special column ahead of the column list.*/
256 /***********************************************************************/
InsertSpecialColumn(PCOL colp)257 PCOL TDBCMG::InsertSpecialColumn(PCOL colp)
258 {
259 if (!colp->IsSpecial())
260 return NULL;
261
262 colp->SetNext(Columns);
263 Columns = colp;
264 return colp;
265 } // end of InsertSpecialColumn
266
267 /***********************************************************************/
268 /* Init: initialize MongoDB processing. */
269 /***********************************************************************/
Init(PGLOBAL g)270 bool TDBCMG::Init(PGLOBAL g)
271 {
272 if (Done)
273 return false;
274
275 /*********************************************************************/
276 /* Open an C connection for this table. */
277 /*********************************************************************/
278 if (!Cmgp)
279 Cmgp = new(g) CMgoConn(g, &Pcg);
280 else if (Cmgp->IsConnected())
281 Cmgp->Close();
282
283 if (Cmgp->Connect(g))
284 return true;
285
286 Done = true;
287 return false;
288 } // end of Init
289
290 /***********************************************************************/
291 /* MONGO Cardinality: returns table size in number of rows. */
292 /***********************************************************************/
Cardinality(PGLOBAL g)293 int TDBCMG::Cardinality(PGLOBAL g)
294 {
295 if (!g)
296 return 1;
297 else if (Cardinal < 0)
298 Cardinal = (!Init(g)) ? Cmgp->CollSize(g) : 0;
299
300 return Cardinal;
301 } // end of Cardinality
302
303 /***********************************************************************/
304 /* MONGO GetMaxSize: returns collection size estimate. */
305 /***********************************************************************/
GetMaxSize(PGLOBAL g)306 int TDBCMG::GetMaxSize(PGLOBAL g)
307 {
308 if (MaxSize < 0)
309 MaxSize = Cardinality(g);
310
311 return MaxSize;
312 } // end of GetMaxSize
313
314 /***********************************************************************/
315 /* OpenDB: Data Base open routine for MONGO access method. */
316 /***********************************************************************/
OpenDB(PGLOBAL g)317 bool TDBCMG::OpenDB(PGLOBAL g)
318 {
319 if (Use == USE_OPEN) {
320 /*******************************************************************/
321 /* Table already open replace it at its beginning. */
322 /*******************************************************************/
323 Cmgp->Rewind();
324 Fpos = -1;
325 return false;
326 } // endif Use
327
328 /*********************************************************************/
329 /* First opening. */
330 /*********************************************************************/
331 if (Pcg.Pipe && Mode != MODE_READ) {
332 strcpy(g->Message, "Pipeline tables are read only");
333 return true;
334 } // endif Pipe
335
336 Use = USE_OPEN; // Do it now in case we are recursively called
337
338 if (Init(g))
339 return true;
340
341 if (Mode == MODE_DELETE && !Next)
342 // Delete all documents
343 return Cmgp->DocDelete(g);
344 else if (Mode == MODE_INSERT)
345 Cmgp->MakeColumnGroups(g);
346
347 return false;
348 } // end of OpenDB
349
350 /***********************************************************************/
351 /* Data Base indexed read routine for ODBC access method. */
352 /***********************************************************************/
ReadKey(PGLOBAL g,OPVAL op,const key_range * kr)353 bool TDBCMG::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
354 {
355 strcpy(g->Message, "MONGO tables are not indexable");
356 return true;
357 } // end of ReadKey
358
359 /***********************************************************************/
360 /* ReadDB: Get next document from a collection. */
361 /***********************************************************************/
ReadDB(PGLOBAL g)362 int TDBCMG::ReadDB(PGLOBAL g)
363 {
364 return Cmgp->ReadNext(g);
365 } // end of ReadDB
366
367 /***********************************************************************/
368 /* WriteDB: Data Base write routine for MGO access method. */
369 /***********************************************************************/
WriteDB(PGLOBAL g)370 int TDBCMG::WriteDB(PGLOBAL g)
371 {
372 return Cmgp->Write(g);
373 } // end of WriteDB
374
375 /***********************************************************************/
376 /* Data Base delete line routine for MGO access method. */
377 /***********************************************************************/
DeleteDB(PGLOBAL g,int irc)378 int TDBCMG::DeleteDB(PGLOBAL g, int irc)
379 {
380 return (irc == RC_OK) ? WriteDB(g) : RC_OK;
381 } // end of DeleteDB
382
383 /***********************************************************************/
384 /* Table close routine for MONGO tables. */
385 /***********************************************************************/
CloseDB(PGLOBAL g)386 void TDBCMG::CloseDB(PGLOBAL g)
387 {
388 Cmgp->Close();
389 Done = false;
390 } // end of CloseDB
391
392 /* ----------------------------- MGOCOL ------------------------------ */
393
394 /***********************************************************************/
395 /* MGOCOL public constructor. */
396 /***********************************************************************/
MGOCOL(PGLOBAL g,PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i)397 MGOCOL::MGOCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
398 : EXTCOL(cdp, tdbp, cprec, i, "MGO")
399 {
400 Tmgp = (PTDBCMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
401 Sgfy = Stringified(Tmgp->Strfy, Name);
402
403 if ((Jpath = cdp->GetFmt())) {
404 int n = strlen(Jpath) - 1;
405
406 if (Jpath[n] == '*') {
407 Jpath = PlugDup(g, cdp->GetFmt());
408 if (Jpath[n - 1] == '.') n--;
409 Jpath[n] = 0;
410 Sgfy = true;
411 } // endif Jpath
412
413 } else
414 Jpath = cdp->GetName();
415
416 } // end of MGOCOL constructor
417
418 /***********************************************************************/
419 /* MGOCOL constructor used for copying columns. */
420 /* tdbp is the pointer to the new table descriptor. */
421 /***********************************************************************/
MGOCOL(MGOCOL * col1,PTDB tdbp)422 MGOCOL::MGOCOL(MGOCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
423 {
424 Tmgp = col1->Tmgp;
425 Jpath = col1->Jpath;
426 Sgfy = col1->Sgfy;
427 } // end of MGOCOL copy constructor
428
429 /***********************************************************************/
430 /* Get path when proj is false or projection path when proj is true. */
431 /***********************************************************************/
GetJpath(PGLOBAL g,bool proj)432 PSZ MGOCOL::GetJpath(PGLOBAL g, bool proj)
433 {
434 if (Jpath) {
435 if (proj) {
436 char *p1, *p2, *projpath = PlugDup(g, Jpath);
437 int i = 0;
438
439 for (p1 = p2 = projpath; *p1; p1++)
440 if (*p1 == '.') {
441 if (!i)
442 *p2++ = *p1;
443
444 i = 1;
445 } else if (i) {
446 if (!isdigit(*p1)) {
447 *p2++ = *p1;
448 i = 0;
449 } // endif p1
450
451 } else
452 *p2++ = *p1;
453
454 if (*(p2 - 1) == '.')
455 p2--;
456
457 *p2 = 0;
458 return projpath;
459 } else
460 return Jpath;
461
462 } else
463 return Name;
464
465 } // end of GetJpath
466
467 /***********************************************************************/
468 /* ReadColumn: */
469 /***********************************************************************/
ReadColumn(PGLOBAL g)470 void MGOCOL::ReadColumn(PGLOBAL g)
471 {
472 Tmgp->Cmgp->GetColumnValue(g, this);
473 } // end of ReadColumn
474
475 /***********************************************************************/
476 /* WriteColumn: */
477 /***********************************************************************/
WriteColumn(PGLOBAL g)478 void MGOCOL::WriteColumn(PGLOBAL g)
479 {
480 // Check whether this node must be written
481 if (Value != To_Val)
482 Value->SetValue_pval(To_Val, FALSE); // Convert the updated value
483
484 } // end of WriteColumn
485
486 /* ---------------------------TDBGOL class --------------------------- */
487
488 /***********************************************************************/
489 /* TDBGOL class constructor. */
490 /***********************************************************************/
TDBGOL(PMGODEF tdp)491 TDBGOL::TDBGOL(PMGODEF tdp) : TDBCAT(tdp)
492 {
493 Topt = tdp->GetTopt();
494 Uri = tdp->Uri;
495 Db = tdp->GetTabschema();
496 } // end of TDBJCL constructor
497
498 /***********************************************************************/
499 /* GetResult: Get the list the JSON file columns. */
500 /***********************************************************************/
GetResult(PGLOBAL g)501 PQRYRES TDBGOL::GetResult(PGLOBAL g)
502 {
503 return MGOColumns(g, Db, Uri, Topt, false);
504 } // end of GetResult
505
506 /* -------------------------- End of mongo --------------------------- */
507