1 /************** tabjmg C++ Program Source Code File (.CPP) *************/
2 /* PROGRAM NAME: tabjmg Version 1.3 */
3 /* (C) Copyright to the author Olivier BERTRAND 2021 */
4 /* This file contains the MongoDB classes using the Java Driver. */
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 "maputil.h"
21 #include "filamtxt.h"
22 #include "tabext.h"
23 #include "tabjmg.h"
24 #include "tabmul.h"
25 #include "checklvl.h"
26 #include "resource.h"
27 #include "mycat.h" // for FNC_COL
28 #include "filter.h"
29
30 #define nullptr 0
31
32 PQRYRES MGOColumns(PGLOBAL g, PCSZ db, PCSZ uri, PTOS topt, bool info);
33 bool Stringified(PCSZ, char*);
34
35 /* -------------------------- Class JMGDISC -------------------------- */
36
37 /***********************************************************************/
38 /* Constructor */
39 /***********************************************************************/
JMGDISC(PGLOBAL g,int * lg)40 JMGDISC::JMGDISC(PGLOBAL g, int *lg) : MGODISC(g, lg)
41 {
42 drv = "Java"; Jcp = NULL; columnid = nullptr; bvnameid = nullptr;
43 } // end of JMGDISC constructor
44
45 /***********************************************************************/
46 /* Initialyze. */
47 /***********************************************************************/
Init(PGLOBAL g)48 bool JMGDISC::Init(PGLOBAL g)
49 {
50 if (!(Jcp = ((TDBJMG*)tmgp)->Jcp)) {
51 strcpy(g->Message, "Init: Jcp is NULL");
52 return true;
53 } else if (Jcp->gmID(g, columnid, "ColumnDesc",
54 "(Ljava/lang/Object;I[II)Ljava/lang/Object;"))
55 return true;
56 else if (Jcp->gmID(g, bvnameid, "ColDescName", "()Ljava/lang/String;"))
57 return true;
58
59 return false;
60 } // end of Init
61
62 /***********************************************************************/
63 /* Analyse passed document. */
64 /***********************************************************************/
Find(PGLOBAL g)65 bool JMGDISC::Find(PGLOBAL g)
66 {
67 return ColDesc(g, nullptr, NULL, NULL, Jcp->m_Ncol, 0);
68 } // end of Find
69
70 /***********************************************************************/
71 /* Analyse passed document. */
72 /***********************************************************************/
ColDesc(PGLOBAL g,jobject obj,char * pcn,char * pfmt,int ncol,int k)73 bool JMGDISC::ColDesc(PGLOBAL g, jobject obj, char *pcn, char *pfmt,
74 int ncol, int k)
75 {
76 const char *key, *utf;
77 char colname[65];
78 char fmt[129];
79 bool rc = true;
80 size_t z;
81 jint *n = nullptr;
82 jstring jkey;
83 jobject jres;
84
85 // Build the java int array
86 jintArray val = Jcp->env->NewIntArray(5);
87
88 if (val == nullptr) {
89 strcpy(g->Message, "Cannot allocate jint array");
90 return true;
91 } else if (!ncol)
92 n = Jcp->env->GetIntArrayElements(val, 0);
93
94 for (int i = 0; i < ncol; i++) {
95 jres = Jcp->env->CallObjectMethod(Jcp->job, columnid, obj, i, val, lvl - k);
96 n = Jcp->env->GetIntArrayElements(val, 0);
97
98 if (Jcp->Check(n[0])) {
99 sprintf(g->Message, "ColDesc: %s", Jcp->Msg);
100 goto err;
101 } else if (!n[0])
102 continue;
103
104 jkey = (jstring)Jcp->env->CallObjectMethod(Jcp->job, bvnameid);
105 utf = Jcp->env->GetStringUTFChars(jkey, nullptr);
106 key = PlugDup(g, utf);
107 Jcp->env->ReleaseStringUTFChars(jkey, utf);
108 Jcp->env->DeleteLocalRef(jkey);
109
110 if (pcn) {
111 strncpy(colname, pcn, 64);
112 colname[64] = 0;
113 z = 65 - strlen(colname);
114 strncat(strncat(colname, "_", z), key, z - 1);
115 } else
116 strcpy(colname, key);
117
118 if (pfmt) {
119 strncpy(fmt, pfmt, 128);
120 fmt[128] = 0;
121 z = 129 - strlen(fmt);
122 strncat(strncat(fmt, ".", z), key, z - 1);
123 } else
124 strcpy(fmt, key);
125
126 if (!jres) {
127 bcol.Type = n[0];
128 bcol.Len = n[1];
129 bcol.Scale = n[2];
130 bcol.Cbn = n[3];
131 AddColumn(g, colname, fmt, k);
132 } else {
133 if (n[0] == 2 && !all)
134 n[4] = MY_MIN(n[4], 1);
135
136 if (ColDesc(g, jres, colname, fmt, n[4], k + 1))
137 goto err;
138
139 } // endif jres
140
141 } // endfor i
142
143 rc = false;
144
145 err:
146 Jcp->env->ReleaseIntArrayElements(val, n, 0);
147 return rc;
148 } // end of ColDesc
149
150 /* --------------------------- Class TDBJMG -------------------------- */
151
152 /***********************************************************************/
153 /* Implementation of the TDBJMG class. */
154 /***********************************************************************/
TDBJMG(PMGODEF tdp)155 TDBJMG::TDBJMG(PMGODEF tdp) : TDBEXT(tdp)
156 {
157 Jcp = NULL;
158 //Cnp = NULL;
159
160 if (tdp) {
161 Ops.Driver = tdp->Tabschema;
162 Ops.Url = tdp->Uri;
163 Ops.Version = tdp->Version;
164 Uri = tdp->Uri;
165 Db_name = tdp->Tabschema;
166 Wrapname = tdp->Wrapname;
167 Coll_name = tdp->Tabname;
168 Options = tdp->Colist;
169 Filter = tdp->Filter;
170 Strfy = tdp->Strfy;
171 B = tdp->Base ? 1 : 0;
172 Pipe = tdp->Pipe && Options != NULL;
173 } else {
174 Ops.Driver = NULL;
175 Ops.Url = NULL;
176 Ops.Version = 0;
177 Uri = NULL;
178 Db_name = NULL;
179 Coll_name = NULL;
180 Options = NULL;
181 Filter = NULL;
182 Strfy = NULL;
183 B = 0;
184 Pipe = false;
185 } // endif tdp
186
187 Ops.User = NULL;
188 Ops.Pwd = NULL;
189 Ops.Scrollable = false;
190 Ops.Fsize = 0;
191 Fpos = -1;
192 N = 0;
193 Done = false;
194 } // end of TDBJMG standard constructor
195
TDBJMG(TDBJMG * tdbp)196 TDBJMG::TDBJMG(TDBJMG *tdbp) : TDBEXT(tdbp)
197 {
198 Uri = tdbp->Uri;
199 Db_name = tdbp->Db_name;;
200 Coll_name = tdbp->Coll_name;
201 Options = tdbp->Options;
202 Filter = tdbp->Filter;
203 Strfy = tdbp->Strfy;
204 B = tdbp->B;
205 Fpos = tdbp->Fpos;
206 N = tdbp->N;
207 Done = tdbp->Done;
208 Pipe = tdbp->Pipe;
209 } // end of TDBJMG copy constructor
210
211 // Used for update
Clone(PTABS t)212 PTDB TDBJMG::Clone(PTABS t)
213 {
214 PTDB tp;
215 PJMGCOL cp1, cp2;
216 PGLOBAL g = t->G;
217
218 tp = new(g) TDBJMG(this);
219
220 for (cp1 = (PJMGCOL)Columns; cp1; cp1 = (PJMGCOL)cp1->GetNext())
221 if (!cp1->IsSpecial()) {
222 cp2 = new(g) JMGCOL(cp1, tp); // Make a copy
223 NewPointer(t, cp1, cp2);
224 } // endif cp1
225
226 return tp;
227 } // end of Clone
228
229 /***********************************************************************/
230 /* Allocate JSN column description block. */
231 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)232 PCOL TDBJMG::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
233 {
234 return new(g) JMGCOL(g, cdp, this, cprec, n);
235 } // end of MakeCol
236
237 /***********************************************************************/
238 /* InsertSpecialColumn: Put a special column ahead of the column list.*/
239 /***********************************************************************/
InsertSpecialColumn(PCOL colp)240 PCOL TDBJMG::InsertSpecialColumn(PCOL colp)
241 {
242 if (!colp->IsSpecial())
243 return NULL;
244
245 colp->SetNext(Columns);
246 Columns = colp;
247 return colp;
248 } // end of InsertSpecialColumn
249
250 /***********************************************************************/
251 /* MONGO Cardinality: returns table size in number of rows. */
252 /***********************************************************************/
Cardinality(PGLOBAL g)253 int TDBJMG::Cardinality(PGLOBAL g)
254 {
255 if (!g)
256 return 1;
257 else if (Cardinal < 0)
258 Cardinal = (!Init(g)) ? Jcp->CollSize(g) : 0;
259
260 return Cardinal;
261 } // end of Cardinality
262
263 /***********************************************************************/
264 /* MONGO GetMaxSize: returns collection size estimate. */
265 /***********************************************************************/
GetMaxSize(PGLOBAL g)266 int TDBJMG::GetMaxSize(PGLOBAL g)
267 {
268 if (MaxSize < 0)
269 MaxSize = Cardinality(g);
270
271 return MaxSize;
272 } // end of GetMaxSize
273
274 /***********************************************************************/
275 /* Init: initialize MongoDB processing. */
276 /***********************************************************************/
Init(PGLOBAL g)277 bool TDBJMG::Init(PGLOBAL g)
278 {
279 if (Done)
280 return false;
281
282 /*********************************************************************/
283 /* Open an JDBC connection for this table. */
284 /* Note: this may not be the proper way to do. Perhaps it is better */
285 /* to test whether a connection is already open for this datasource */
286 /* and if so to allocate just a new result set. But this only for */
287 /* drivers allowing concurency in getting results ??? */
288 /*********************************************************************/
289 if (!Jcp)
290 Jcp = new(g) JMgoConn(g, Coll_name, Wrapname);
291 else if (Jcp->IsOpen())
292 Jcp->Close();
293
294 if (Jcp->Connect(&Ops))
295 return true;
296
297 Done = true;
298 return false;
299 } // end of Init
300
301 /***********************************************************************/
302 /* OpenDB: Data Base open routine for MONGO access method. */
303 /***********************************************************************/
OpenDB(PGLOBAL g)304 bool TDBJMG::OpenDB(PGLOBAL g)
305 {
306 if (Use == USE_OPEN) {
307 /*******************************************************************/
308 /* Table already open replace it at its beginning. */
309 /*******************************************************************/
310 if (Jcp->Rewind())
311 return true;
312
313 Fpos = -1;
314 return false;
315 } // endif Use
316
317 /*********************************************************************/
318 /* First opening. */
319 /*********************************************************************/
320 if (Pipe && Mode != MODE_READ) {
321 strcpy(g->Message, "Pipeline tables are read only");
322 return true;
323 } // endif Pipe
324
325 Use = USE_OPEN; // Do it now in case we are recursively called
326
327 if (Init(g))
328 return true;
329
330 if (Jcp->GetMethodId(g, Mode))
331 return true;
332
333 if (Mode == MODE_DELETE && !Next) {
334 // Delete all documents
335 if (!Jcp->MakeCursor(g, this, "all", Filter, false))
336 if (Jcp->DocDelete(g, true) == RC_OK)
337 return false;
338
339 return true;
340 } // endif Mode
341
342 if (Mode == MODE_INSERT)
343 Jcp->MakeColumnGroups(g, this);
344
345 if (Mode != MODE_UPDATE)
346 return Jcp->MakeCursor(g, this, Options, Filter, Pipe);
347
348 return false;
349 } // end of OpenDB
350
351 /***********************************************************************/
352 /* Data Base indexed read routine for ODBC access method. */
353 /***********************************************************************/
ReadKey(PGLOBAL g,OPVAL op,const key_range * kr)354 bool TDBJMG::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
355 {
356 strcpy(g->Message, "MONGO tables are not indexable");
357 return true;
358 } // end of ReadKey
359
360 /***********************************************************************/
361 /* ReadDB: Get next document from a collection. */
362 /***********************************************************************/
ReadDB(PGLOBAL g)363 int TDBJMG::ReadDB(PGLOBAL g)
364 {
365 int rc = RC_OK;
366
367 if (!N && Mode == MODE_UPDATE)
368 if (Jcp->MakeCursor(g, this, Options, Filter, Pipe))
369 return RC_FX;
370
371 if (++CurNum >= Rbuf) {
372 Rbuf = Jcp->Fetch();
373 Curpos = Fpos + 1;
374 CurNum = 0;
375 N++;
376 } // endif CurNum
377
378 rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
379
380 return rc;
381 } // end of ReadDB
382
383 /***********************************************************************/
384 /* WriteDB: Data Base write routine for DOS access method. */
385 /***********************************************************************/
WriteDB(PGLOBAL g)386 int TDBJMG::WriteDB(PGLOBAL g)
387 {
388 int rc = RC_OK;
389
390 if (Mode == MODE_INSERT) {
391 rc = Jcp->DocWrite(g, NULL);
392 } else if (Mode == MODE_DELETE) {
393 rc = Jcp->DocDelete(g, false);
394 } else if (Mode == MODE_UPDATE) {
395 rc = Jcp->DocUpdate(g, this);
396 } // endif Mode
397
398 return rc;
399 } // end of WriteDB
400
401 /***********************************************************************/
402 /* Data Base delete line routine for ODBC access method. */
403 /***********************************************************************/
DeleteDB(PGLOBAL g,int irc)404 int TDBJMG::DeleteDB(PGLOBAL g, int irc)
405 {
406 return (irc == RC_OK) ? WriteDB(g) : RC_OK;
407 } // end of DeleteDB
408
409 /***********************************************************************/
410 /* Table close routine for MONGO tables. */
411 /***********************************************************************/
CloseDB(PGLOBAL g)412 void TDBJMG::CloseDB(PGLOBAL g)
413 {
414 Jcp->Close();
415 Done = false;
416 } // end of CloseDB
417
418 /* ----------------------------- JMGCOL ------------------------------ */
419
420 /***********************************************************************/
421 /* JMGCOL public constructor. */
422 /***********************************************************************/
JMGCOL(PGLOBAL g,PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i)423 JMGCOL::JMGCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
424 : EXTCOL(cdp, tdbp, cprec, i, "MGO")
425 {
426 Tmgp = (PTDBJMG)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
427 Sgfy = Stringified(Tmgp->Strfy, Name);
428
429 if ((Jpath = cdp->GetFmt())) {
430 int n = strlen(Jpath);
431
432 if (n && Jpath[n - 1] == '*') {
433 Jpath = PlugDup(g, cdp->GetFmt());
434
435 if (--n) {
436 if (Jpath[n - 1] == '.') n--;
437 Jpath[n] = 0;
438 } // endif n
439
440 Sgfy = true;
441 } // endif Jpath
442
443 } else
444 Jpath = cdp->GetName();
445
446 } // end of JMGCOL constructor
447
448 /***********************************************************************/
449 /* JMGCOL constructor used for copying columns. */
450 /* tdbp is the pointer to the new table descriptor. */
451 /***********************************************************************/
JMGCOL(JMGCOL * col1,PTDB tdbp)452 JMGCOL::JMGCOL(JMGCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
453 {
454 Tmgp = col1->Tmgp;
455 Jpath = col1->Jpath;
456 Sgfy = col1->Sgfy;
457 } // end of JMGCOL copy constructor
458
459 /***********************************************************************/
460 /* Get path when proj is false or projection path when proj is true. */
461 /***********************************************************************/
GetJpath(PGLOBAL g,bool proj)462 PSZ JMGCOL::GetJpath(PGLOBAL g, bool proj)
463 {
464 if (Jpath) {
465 if (proj) {
466 char* p1, * p2, * projpath = PlugDup(g, Jpath);
467 int i = 0;
468
469 for (p1 = p2 = projpath; *p1; p1++)
470 if (*p1 == '.') {
471 if (!i)
472 *p2++ = *p1;
473
474 i = 1;
475 } else if (i) {
476 if (!isdigit(*p1)) {
477 *p2++ = *p1;
478 i = 0;
479 } // endif p1
480
481 } else
482 *p2++ = *p1;
483
484 if (*(p2 - 1) == '.')
485 p2--;
486
487 *p2 = 0;
488 return projpath;
489 } else
490 return Jpath;
491
492 } else
493 return Name;
494
495 } // end of GetJpath
496
497 #if 0
498 /***********************************************************************/
499 /* Mini: used to suppress blanks to json strings. */
500 /***********************************************************************/
501 char *JMGCOL::Mini(PGLOBAL g, const bson_t *bson, bool b)
502 {
503 char *s, *str = NULL;
504 int i, k = 0;
505 bool ok = true;
506
507 if (b)
508 s = str = bson_array_as_json(bson, NULL);
509 else
510 s = str = bson_as_json(bson, NULL);
511
512 for (i = 0; i < Long && s[i]; i++) {
513 switch (s[i]) {
514 case ' ':
515 if (ok) continue;
516 break;
517 case '"':
518 ok = !ok;
519 default:
520 break;
521 } // endswitch s[i]
522
523 Mbuf[k++] = s[i];
524 } // endfor i
525
526 bson_free(str);
527
528 if (i >= Long) {
529 sprintf(g->Message, "Value too long for column %s", Name);
530 throw (int)TYPE_AM_MGO;
531 } // endif i
532
533 Mbuf[k] = 0;
534 return Mbuf;
535 } // end of Mini
536 #endif // 0
537
538 /***********************************************************************/
539 /* ReadColumn: */
540 /***********************************************************************/
ReadColumn(PGLOBAL g)541 void JMGCOL::ReadColumn(PGLOBAL g)
542 {
543 Value->SetValue_psz(Tmgp->Jcp->GetColumnValue(Jpath));
544 } // end of ReadColumn
545
546 /***********************************************************************/
547 /* WriteColumn: */
548 /***********************************************************************/
WriteColumn(PGLOBAL g)549 void JMGCOL::WriteColumn(PGLOBAL g)
550 {
551 // Check whether this node must be written
552 if (Value != To_Val)
553 Value->SetValue_pval(To_Val, FALSE); // Convert the updated value
554
555 } // end of WriteColumn
556
557 #if 0
558 /***********************************************************************/
559 /* AddValue: Add column value to the document to insert or update. */
560 /***********************************************************************/
561 bool JMGCOL::AddValue(PGLOBAL g, bson_t *doc, char *key, bool upd)
562 {
563 bool rc = false;
564
565 if (Value->IsNull()) {
566 if (upd)
567 rc = BSON_APPEND_NULL(doc, key);
568 else
569 return false;
570
571 } else switch (Buf_Type) {
572 case TYPE_STRING:
573 rc = BSON_APPEND_UTF8(doc, key, Value->GetCharValue());
574 break;
575 case TYPE_INT:
576 case TYPE_SHORT:
577 rc = BSON_APPEND_INT32(doc, key, Value->GetIntValue());
578 break;
579 case TYPE_TINY:
580 rc = BSON_APPEND_BOOL(doc, key, Value->GetIntValue());
581 break;
582 case TYPE_BIGINT:
583 rc = BSON_APPEND_INT64(doc, key, Value->GetBigintValue());
584 break;
585 case TYPE_DOUBLE:
586 rc = BSON_APPEND_DOUBLE(doc, key, Value->GetFloatValue());
587 break;
588 case TYPE_DECIM:
589 {bson_decimal128_t dec;
590
591 if (bson_decimal128_from_string(Value->GetCharValue(), &dec))
592 rc = BSON_APPEND_DECIMAL128(doc, key, &dec);
593
594 } break;
595 case TYPE_DATE:
596 rc = BSON_APPEND_DATE_TIME(doc, key, Value->GetBigintValue() * 1000);
597 break;
598 default:
599 sprintf(g->Message, "Type %d not supported yet", Buf_Type);
600 return true;
601 } // endswitch Buf_Type
602
603 if (!rc) {
604 strcpy(g->Message, "Adding value failed");
605 return true;
606 } else
607 return false;
608
609 } // end of AddValue
610 #endif // 0
611
612 /* -------------------------- TDBJGL class --------------------------- */
613
614 /***********************************************************************/
615 /* TDBJGL class constructor. */
616 /***********************************************************************/
TDBJGL(PMGODEF tdp)617 TDBJGL::TDBJGL(PMGODEF tdp) : TDBCAT(tdp)
618 {
619 Topt = tdp->GetTopt();
620 Uri = tdp->Uri;
621 Db = tdp->GetTabschema();
622 } // end of TDBJCL constructor
623
624 /***********************************************************************/
625 /* GetResult: Get the list the MongoDB collection columns. */
626 /***********************************************************************/
GetResult(PGLOBAL g)627 PQRYRES TDBJGL::GetResult(PGLOBAL g)
628 {
629 return MGOColumns(g, Db, Uri, Topt, false);
630 } // end of GetResult
631
632 /* -------------------------- End of mongo --------------------------- */
633