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 /***********************************************************************/ 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 /***********************************************************************/ 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 /***********************************************************************/ 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 /***********************************************************************/ 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 /***********************************************************************/ 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 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 /***********************************************************************/ 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 /***********************************************************************/ 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