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