| 1 | /************ JMgoConn C++ Functions Source Code File (.CPP) ***********/ |
| 2 | /* Name: JMgoConn.CPP Version 1.1 */ |
| 3 | /* */ |
| 4 | /* (C) Copyright to the author Olivier BERTRAND 2017 */ |
| 5 | /* */ |
| 6 | /* This file contains the MongoDB Java connection classes functions. */ |
| 7 | /***********************************************************************/ |
| 8 | |
| 9 | /***********************************************************************/ |
| 10 | /* Include relevant MariaDB header file. */ |
| 11 | /***********************************************************************/ |
| 12 | #include <my_global.h> |
| 13 | |
| 14 | /***********************************************************************/ |
| 15 | /* Required objects includes. */ |
| 16 | /***********************************************************************/ |
| 17 | #include "global.h" |
| 18 | #include "plgdbsem.h" |
| 19 | #include "colblk.h" |
| 20 | #include "xobject.h" |
| 21 | #include "xtable.h" |
| 22 | #include "filter.h" |
| 23 | #include "jmgoconn.h" |
| 24 | |
| 25 | #define nullptr 0 |
| 26 | |
| 27 | bool IsNum(PSZ s); |
| 28 | bool MakeSelector(PGLOBAL g, PFIL fp, PSTRG s); |
| 29 | |
| 30 | /* --------------------------- Class JNCOL --------------------------- */ |
| 31 | |
| 32 | /***********************************************************************/ |
| 33 | /* Add a column in the column list. */ |
| 34 | /***********************************************************************/ |
| 35 | void JNCOL::AddCol(PGLOBAL g, PCOL colp, PSZ jp) |
| 36 | { |
| 37 | char *p; |
| 38 | PJKC kp, kcp; |
| 39 | |
| 40 | if ((p = strchr(jp, '.'))) { |
| 41 | PJNCOL icp; |
| 42 | |
| 43 | *p++ = 0; |
| 44 | |
| 45 | for (kp = Klist; kp; kp = kp->Next) |
| 46 | if (kp->Jncolp && !strcmp(jp, kp->Key)) |
| 47 | break; |
| 48 | |
| 49 | if (!kp) { |
| 50 | icp = new(g) JNCOL(IsNum(p)); |
| 51 | kcp = (PJKC)PlugSubAlloc(g, NULL, sizeof(JKCOL)); |
| 52 | kcp->Next = NULL; |
| 53 | kcp->Jncolp = icp; |
| 54 | kcp->Colp = NULL; |
| 55 | |
| 56 | if (Array) { |
| 57 | kcp->Key = NULL; |
| 58 | kcp->N = atoi(p); |
| 59 | } else { |
| 60 | kcp->Key = PlugDup(g, jp); |
| 61 | kcp->N = 0; |
| 62 | } // endif Array |
| 63 | |
| 64 | if (Klist) { |
| 65 | for (kp = Klist; kp->Next; kp = kp->Next); |
| 66 | |
| 67 | kp->Next = kcp; |
| 68 | } else |
| 69 | Klist = kcp; |
| 70 | |
| 71 | } else |
| 72 | icp = kp->Jncolp; |
| 73 | |
| 74 | *(p - 1) = '.'; |
| 75 | icp->AddCol(g, colp, p); |
| 76 | } else { |
| 77 | kcp = (PJKC)PlugSubAlloc(g, NULL, sizeof(JKCOL)); |
| 78 | |
| 79 | kcp->Next = NULL; |
| 80 | kcp->Jncolp = NULL; |
| 81 | kcp->Colp = colp; |
| 82 | |
| 83 | if (Array) { |
| 84 | kcp->Key = NULL; |
| 85 | kcp->N = atoi(jp); |
| 86 | } else { |
| 87 | kcp->Key = jp; |
| 88 | kcp->N = 0; |
| 89 | } // endif Array |
| 90 | |
| 91 | if (Klist) { |
| 92 | for (kp = Klist; kp->Next; kp = kp->Next); |
| 93 | |
| 94 | kp->Next = kcp; |
| 95 | } else |
| 96 | Klist = kcp; |
| 97 | |
| 98 | } // endif jp |
| 99 | |
| 100 | } // end of AddCol |
| 101 | |
| 102 | /***********************************************************************/ |
| 103 | /* JMgoConn construction/destruction. */ |
| 104 | /***********************************************************************/ |
| 105 | JMgoConn::JMgoConn(PGLOBAL g, PCSZ collname, PCSZ wrapper) |
| 106 | : JAVAConn(g, wrapper) |
| 107 | { |
| 108 | CollName = collname; |
| 109 | readid = fetchid = getdocid = objfldid = fcollid = acollid = |
| 110 | mkdocid = docaddid = mkarid = araddid = insertid = updateid = |
| 111 | deleteid = gcollid = countid = rewindid = nullptr; |
| 112 | DiscFunc = "MongoDisconnect" ; |
| 113 | Fpc = NULL; |
| 114 | m_Fetch = 0; |
| 115 | m_Ncol = 0; |
| 116 | m_Version = 0; |
| 117 | } // end of JMgoConn |
| 118 | |
| 119 | /***********************************************************************/ |
| 120 | /* AddJars: add some jar file to the Class path. */ |
| 121 | /***********************************************************************/ |
| 122 | void JMgoConn::AddJars(PSTRG jpop, char sep) |
| 123 | { |
| 124 | #if defined(DEVELOPMENT) |
| 125 | if (m_Version == 2) { |
| 126 | jpop->Append(sep); |
| 127 | // jpop->Append("C:/Eclipse/workspace/MongoWrap2/bin"); |
| 128 | jpop->Append(sep); |
| 129 | jpop->Append("C:/mongo-java-driver/mongo-java-driver-2.13.3.jar" ); |
| 130 | } else { |
| 131 | jpop->Append(sep); |
| 132 | // jpop->Append("C:/Eclipse/workspace/MongoWrap3/bin"); |
| 133 | // jpop->Append("C:/Program Files/MariaDB 10.1/lib/plugin/JavaWrappers.jar"); |
| 134 | jpop->Append(sep); |
| 135 | jpop->Append("C:/mongo-java-driver/mongo-java-driver-3.4.2.jar" ); |
| 136 | } // endif m_Version |
| 137 | #endif // DEVELOPMENT |
| 138 | } // end of AddJars |
| 139 | |
| 140 | /***********************************************************************/ |
| 141 | /* Connect: connect to a data source. */ |
| 142 | /***********************************************************************/ |
| 143 | bool JMgoConn::Connect(PJPARM sop) |
| 144 | { |
| 145 | bool err = false; |
| 146 | jint rc; |
| 147 | jboolean brc; |
| 148 | jstring cln; |
| 149 | PGLOBAL& g = m_G; |
| 150 | |
| 151 | m_Version = sop->Version; |
| 152 | |
| 153 | /*******************************************************************/ |
| 154 | /* Create or attach a JVM. */ |
| 155 | /*******************************************************************/ |
| 156 | if (Open(g)) |
| 157 | return true; |
| 158 | |
| 159 | /*******************************************************************/ |
| 160 | /* Connect to MongoDB. */ |
| 161 | /*******************************************************************/ |
| 162 | jmethodID cid = nullptr; |
| 163 | |
| 164 | if (gmID(g, cid, "MongoConnect" , "([Ljava/lang/String;)I" )) |
| 165 | return true; |
| 166 | |
| 167 | // Build the java string array |
| 168 | jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4 |
| 169 | env->FindClass("java/lang/String" ), NULL); // Strings |
| 170 | |
| 171 | //m_Scrollable = sop->Scrollable; |
| 172 | //m_RowsetSize = sop->Fsize; |
| 173 | |
| 174 | // change some elements |
| 175 | if (sop->Driver) |
| 176 | env->SetObjectArrayElement(parms, 0, env->NewStringUTF(sop->Url)); |
| 177 | |
| 178 | if (sop->Url) |
| 179 | env->SetObjectArrayElement(parms, 1, env->NewStringUTF(sop->Driver)); |
| 180 | |
| 181 | if (sop->User) |
| 182 | env->SetObjectArrayElement(parms, 2, env->NewStringUTF(sop->User)); |
| 183 | |
| 184 | if (sop->Pwd) |
| 185 | env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd)); |
| 186 | |
| 187 | // call method |
| 188 | rc = env->CallIntMethod(job, cid, parms); |
| 189 | err = Check(rc); |
| 190 | env->DeleteLocalRef(parms); // Not used anymore |
| 191 | |
| 192 | if (err) { |
| 193 | sprintf(g->Message, "Connecting: %s rc=%d" , Msg, (int)rc); |
| 194 | return true; |
| 195 | } // endif Msg |
| 196 | |
| 197 | /*********************************************************************/ |
| 198 | /* Get the collection. */ |
| 199 | /*********************************************************************/ |
| 200 | if (gmID(g, gcollid, "GetCollection" , "(Ljava/lang/String;)Z" )) |
| 201 | return true; |
| 202 | |
| 203 | cln = env->NewStringUTF(CollName); |
| 204 | brc = env->CallBooleanMethod(job, gcollid, cln); |
| 205 | env->DeleteLocalRef(cln); |
| 206 | |
| 207 | if (Check(brc ? -1 : 0)) { |
| 208 | sprintf(g->Message, "GetCollection: %s" , Msg); |
| 209 | return true; |
| 210 | } // endif Msg |
| 211 | |
| 212 | m_Connected = true; |
| 213 | return false; |
| 214 | } // end of Connect |
| 215 | |
| 216 | /***********************************************************************/ |
| 217 | /* CollSize: returns the number of documents in the collection. */ |
| 218 | /***********************************************************************/ |
| 219 | int JMgoConn::CollSize(PGLOBAL g) |
| 220 | { |
| 221 | if (!gmID(g, countid, "GetCollSize" , "()J" )) { |
| 222 | jlong card = env->CallLongMethod(job, countid); |
| 223 | |
| 224 | return (int)card; |
| 225 | } else |
| 226 | return 2; // Make MariaDB happy |
| 227 | |
| 228 | } // end of CollSize |
| 229 | |
| 230 | /***********************************************************************/ |
| 231 | /* OpenDB: Data Base open routine for MONGO access method. */ |
| 232 | /***********************************************************************/ |
| 233 | bool JMgoConn::MakeCursor(PGLOBAL g, PTDB tdbp, PCSZ options, |
| 234 | PCSZ filter, bool pipe) |
| 235 | { |
| 236 | const char *p; |
| 237 | bool b = false, id = (tdbp->GetMode() != MODE_READ), all = false; |
| 238 | uint len; |
| 239 | PCOL cp; |
| 240 | PSZ jp; |
| 241 | PCSZ op = NULL, sf = NULL, Options = options; |
| 242 | PSTRG s = NULL; |
| 243 | PFIL filp = tdbp->GetFilter(); |
| 244 | |
| 245 | if (Options && !stricmp(Options, "all" )) { |
| 246 | Options = NULL; |
| 247 | all = true; |
| 248 | } // endif Options |
| 249 | |
| 250 | for (cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) |
| 251 | if (!strcmp(cp->GetName(), "_id" )) |
| 252 | id = true; |
| 253 | else if (cp->GetFmt() && !strcmp(cp->GetFmt(), "*" ) && (!Options || pipe)) |
| 254 | all = true; |
| 255 | |
| 256 | if (pipe && Options) { |
| 257 | if (trace(1)) |
| 258 | htrc("Pipeline: %s\n" , Options); |
| 259 | |
| 260 | p = strrchr(Options, ']'); |
| 261 | |
| 262 | if (!p) { |
| 263 | strcpy(g->Message, "Missing ] in pipeline" ); |
| 264 | return true; |
| 265 | } else |
| 266 | *(char*)p = 0; |
| 267 | |
| 268 | s = new(g) STRING(g, 1023, (PSZ)Options); |
| 269 | |
| 270 | if (filp) { |
| 271 | s->Append(",{\"$match\":" ); |
| 272 | |
| 273 | if (MakeSelector(g, filp, s)) { |
| 274 | strcpy(g->Message, "Failed making selector" ); |
| 275 | return NULL; |
| 276 | } else |
| 277 | s->Append('}'); |
| 278 | |
| 279 | tdbp->SetFilter(NULL); // Not needed anymore |
| 280 | } // endif To_Filter |
| 281 | |
| 282 | if (!all && tdbp->GetColumns()) { |
| 283 | // Project list |
| 284 | len = s->GetLength(); |
| 285 | s->Append(",{\"$project\":{\"" ); |
| 286 | |
| 287 | if (!id) |
| 288 | s->Append("_id\":0,\"" ); |
| 289 | |
| 290 | for (PCOL cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) { |
| 291 | if (b) |
| 292 | s->Append(",\"" ); |
| 293 | else |
| 294 | b = true; |
| 295 | |
| 296 | if ((jp = cp->GetJpath(g, true))) |
| 297 | s->Append(jp); |
| 298 | else { |
| 299 | s->Truncate(len); |
| 300 | goto nop; |
| 301 | } // endif Jpath |
| 302 | |
| 303 | s->Append("\":1" ); |
| 304 | } // endfor cp |
| 305 | |
| 306 | s->Append("}}" ); |
| 307 | } // endif all |
| 308 | |
| 309 | nop: |
| 310 | s->Append("]}" ); |
| 311 | s->Resize(s->GetLength() + 1); |
| 312 | *(char*)p = ']'; // Restore Colist for discovery |
| 313 | p = s->GetStr(); |
| 314 | |
| 315 | if (trace(33)) |
| 316 | htrc("New Pipeline: %s\n" , p); |
| 317 | |
| 318 | return AggregateCollection(p); |
| 319 | } else { |
| 320 | if (filter || filp) { |
| 321 | if (trace(1)) { |
| 322 | if (filter) |
| 323 | htrc("Filter: %s\n" , filter); |
| 324 | |
| 325 | if (filp) { |
| 326 | char buf[512]; |
| 327 | |
| 328 | filp->Prints(g, buf, 511); |
| 329 | htrc("To_Filter: %s\n" , buf); |
| 330 | } // endif To_Filter |
| 331 | |
| 332 | } // endif trace |
| 333 | |
| 334 | s = new(g) STRING(g, 1023, (PSZ)filter); |
| 335 | len = s->GetLength(); |
| 336 | |
| 337 | if (filp) { |
| 338 | if (filter) |
| 339 | s->Append(','); |
| 340 | |
| 341 | if (MakeSelector(g, filp, s)) { |
| 342 | strcpy(g->Message, "Failed making selector" ); |
| 343 | return NULL; |
| 344 | } // endif Selector |
| 345 | |
| 346 | tdbp->SetFilter(NULL); // Not needed anymore |
| 347 | } // endif To_Filter |
| 348 | |
| 349 | if (trace(33)) |
| 350 | htrc("selector: %s\n" , s->GetStr()); |
| 351 | |
| 352 | s->Resize(s->GetLength() + 1); |
| 353 | sf = PlugDup(g, s->GetStr()); |
| 354 | } // endif Filter |
| 355 | |
| 356 | if (!all) { |
| 357 | if (Options && *Options) { |
| 358 | if (trace(1)) |
| 359 | htrc("options=%s\n" , Options); |
| 360 | |
| 361 | op = Options; |
| 362 | } else if (tdbp->GetColumns()) { |
| 363 | // Projection list |
| 364 | if (s) |
| 365 | s->Set("{\"" ); |
| 366 | else |
| 367 | s = new(g) STRING(g, 511, "{\"" ); |
| 368 | |
| 369 | if (!id) |
| 370 | s->Append("_id\":0,\"" ); |
| 371 | |
| 372 | for (PCOL cp = tdbp->GetColumns(); cp; cp = cp->GetNext()) { |
| 373 | if (b) |
| 374 | s->Append(",\"" ); |
| 375 | else |
| 376 | b = true; |
| 377 | |
| 378 | if ((jp = cp->GetJpath(g, true))) |
| 379 | s->Append(jp); |
| 380 | else { |
| 381 | // Can this happen? |
| 382 | htrc("Fail getting projection path of %s\n" , cp->GetName()); |
| 383 | goto nope; |
| 384 | } // endif Jpath |
| 385 | |
| 386 | s->Append("\":1" ); |
| 387 | } // endfor cp |
| 388 | |
| 389 | s->Append("}" ); |
| 390 | s->Resize(s->GetLength() + 1); |
| 391 | op = s->GetStr(); |
| 392 | } else { |
| 393 | // count(*) ? |
| 394 | op = "{\"_id\":1}" ; |
| 395 | } // endif Options |
| 396 | |
| 397 | } // endif all |
| 398 | |
| 399 | nope: |
| 400 | return FindCollection(sf, op); |
| 401 | } // endif Pipe |
| 402 | |
| 403 | } // end of MakeCursor |
| 404 | |
| 405 | /***********************************************************************/ |
| 406 | /* Find a collection and make cursor. */ |
| 407 | /***********************************************************************/ |
| 408 | bool JMgoConn::FindCollection(PCSZ query, PCSZ proj) |
| 409 | { |
| 410 | bool rc = true; |
| 411 | jboolean brc; |
| 412 | jstring qry = nullptr, prj = nullptr; |
| 413 | PGLOBAL& g = m_G; |
| 414 | |
| 415 | // Get the methods used to execute a query and get the result |
| 416 | if (!gmID(g, fcollid, "FindColl" , "(Ljava/lang/String;Ljava/lang/String;)Z" )) { |
| 417 | if (query) |
| 418 | qry = env->NewStringUTF(query); |
| 419 | |
| 420 | if (proj) |
| 421 | prj = env->NewStringUTF(proj); |
| 422 | |
| 423 | brc = env->CallBooleanMethod(job, fcollid, qry, prj); |
| 424 | |
| 425 | if (!Check(brc ? -1 : 0)) { |
| 426 | rc = false; |
| 427 | } else |
| 428 | sprintf(g->Message, "FindColl: %s" , Msg); |
| 429 | |
| 430 | if (query) |
| 431 | env->DeleteLocalRef(qry); |
| 432 | |
| 433 | if (proj) |
| 434 | env->DeleteLocalRef(prj); |
| 435 | |
| 436 | } // endif xqid |
| 437 | |
| 438 | return rc; |
| 439 | } // end of FindCollection |
| 440 | |
| 441 | /***********************************************************************/ |
| 442 | /* Find a collection and make cursor. */ |
| 443 | /***********************************************************************/ |
| 444 | bool JMgoConn::AggregateCollection(PCSZ pipeline) |
| 445 | { |
| 446 | bool rc = true; |
| 447 | jboolean brc; |
| 448 | jstring pip = nullptr; |
| 449 | PGLOBAL& g = m_G; |
| 450 | |
| 451 | // Get the methods used to execute a query and get the result |
| 452 | if (!gmID(g, acollid, "AggregateColl" , "(Ljava/lang/String;)Z" )) { |
| 453 | pip = env->NewStringUTF(pipeline); |
| 454 | |
| 455 | brc = env->CallBooleanMethod(job, acollid, pip); |
| 456 | |
| 457 | if (!Check(brc ? -1 : 0)) { |
| 458 | rc = false; |
| 459 | } else |
| 460 | sprintf(g->Message, "AggregateColl: %s" , Msg); |
| 461 | |
| 462 | env->DeleteLocalRef(pip); |
| 463 | } // endif acollid |
| 464 | |
| 465 | return rc; |
| 466 | } // end of AggregateCollection |
| 467 | |
| 468 | /***********************************************************************/ |
| 469 | /* Fetch next row. */ |
| 470 | /***********************************************************************/ |
| 471 | int JMgoConn::Fetch(int pos) |
| 472 | { |
| 473 | jint rc = JNI_ERR; |
| 474 | PGLOBAL& g = m_G; |
| 475 | |
| 476 | //if (m_Full) // Result set has one row |
| 477 | // return 1; |
| 478 | |
| 479 | //if (pos) { |
| 480 | // if (!m_Scrollable) { |
| 481 | // strcpy(g->Message, "Cannot fetch(pos) if FORWARD ONLY"); |
| 482 | // return rc; |
| 483 | // } else if (gmID(m_G, fetchid, "Fetch", "(I)Z")) |
| 484 | // return rc; |
| 485 | |
| 486 | // if (env->CallBooleanMethod(job, fetchid, pos)) |
| 487 | // rc = m_Rows; |
| 488 | |
| 489 | //} else { |
| 490 | if (gmID(g, readid, "ReadNext" , "()I" )) |
| 491 | return (int)rc; |
| 492 | |
| 493 | rc = env->CallIntMethod(job, readid); |
| 494 | |
| 495 | if (!Check(rc)) { |
| 496 | //if (rc == 0) |
| 497 | // m_Full = (m_Fetch == 1); |
| 498 | //else |
| 499 | // m_Fetch++; |
| 500 | |
| 501 | m_Ncol = (int)rc; |
| 502 | rc = MY_MIN(rc, 1); |
| 503 | m_Rows += rc; |
| 504 | } else |
| 505 | sprintf(g->Message, "Fetch: %s" , Msg); |
| 506 | |
| 507 | //} // endif pos |
| 508 | |
| 509 | return rc; |
| 510 | } // end of Fetch |
| 511 | |
| 512 | /***********************************************************************/ |
| 513 | /* Get the Json string of the current document. */ |
| 514 | /***********************************************************************/ |
| 515 | PSZ JMgoConn::GetDocument(void) |
| 516 | { |
| 517 | PGLOBAL& g = m_G; |
| 518 | PSZ doc = NULL; |
| 519 | jstring jdc; |
| 520 | |
| 521 | if (!gmID(g, getdocid, "GetDoc" , "()Ljava/lang/String;" )) { |
| 522 | jdc = (jstring)env->CallObjectMethod(job, getdocid); |
| 523 | |
| 524 | if (jdc) |
| 525 | doc = (PSZ)env->GetStringUTFChars(jdc, (jboolean)false); |
| 526 | |
| 527 | } // endif getdocid |
| 528 | |
| 529 | return doc; |
| 530 | } // end of GetDocument |
| 531 | |
| 532 | /***********************************************************************/ |
| 533 | /* Group columns for inserting or updating. */ |
| 534 | /***********************************************************************/ |
| 535 | void JMgoConn::MakeColumnGroups(PGLOBAL g, PTDB tdbp) |
| 536 | { |
| 537 | Fpc = new(g) JNCOL(false); |
| 538 | |
| 539 | for (PCOL colp = tdbp->GetColumns(); colp; colp = colp->GetNext()) |
| 540 | if (!colp->IsSpecial()) |
| 541 | Fpc->AddCol(g, colp, colp->GetJpath(g, false)); |
| 542 | |
| 543 | } // end of MakeColumnGroups |
| 544 | |
| 545 | /***********************************************************************/ |
| 546 | /* Get additional method ID. */ |
| 547 | /***********************************************************************/ |
| 548 | bool JMgoConn::GetMethodId(PGLOBAL g, MODE mode) |
| 549 | { |
| 550 | if (mode == MODE_UPDATE) { |
| 551 | if (gmID(g, mkdocid, "MakeDocument" , "()Ljava/lang/Object;" )) |
| 552 | return true; |
| 553 | |
| 554 | if (gmID(g, docaddid, "DocAdd" , |
| 555 | "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z" )) |
| 556 | return true; |
| 557 | |
| 558 | if (gmID(g, updateid, "CollUpdate" , "(Ljava/lang/Object;)J" )) |
| 559 | return true; |
| 560 | |
| 561 | } else if (mode == MODE_INSERT) { |
| 562 | if (gmID(g, mkdocid, "MakeDocument" , "()Ljava/lang/Object;" )) |
| 563 | return true; |
| 564 | |
| 565 | if (gmID(g, docaddid, "DocAdd" , |
| 566 | "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z" )) |
| 567 | return true; |
| 568 | |
| 569 | if (gmID(g, mkarid, "MakeArray" , "()Ljava/lang/Object;" )) |
| 570 | return true; |
| 571 | |
| 572 | if (gmID(g, araddid, "ArrayAdd" , "(Ljava/lang/Object;ILjava/lang/Object;)Z" )) |
| 573 | return true; |
| 574 | |
| 575 | if (gmID(g, insertid, "CollInsert" , "(Ljava/lang/Object;)Z" )) |
| 576 | return true; |
| 577 | |
| 578 | } else if (mode == MODE_DELETE) |
| 579 | if (gmID(g, deleteid, "CollDelete" , "(Z)J" )) |
| 580 | return true; |
| 581 | |
| 582 | return gmID(g, rewindid, "Rewind" , "()Z" ); |
| 583 | } // end of GetMethodId |
| 584 | |
| 585 | /***********************************************************************/ |
| 586 | /* MakeObject. */ |
| 587 | /***********************************************************************/ |
| 588 | jobject JMgoConn::MakeObject(PGLOBAL g, PCOL colp, bool&error ) |
| 589 | { |
| 590 | jclass cls; |
| 591 | jmethodID cns = nullptr; // Constructor |
| 592 | jobject val = nullptr; |
| 593 | PVAL valp = colp->GetValue(); |
| 594 | |
| 595 | error = false; |
| 596 | |
| 597 | if (valp->IsNull()) |
| 598 | return NULL; |
| 599 | |
| 600 | try { |
| 601 | switch (valp->GetType()) { |
| 602 | case TYPE_STRING: |
| 603 | val = env->NewStringUTF(valp->GetCharValue()); |
| 604 | break; |
| 605 | case TYPE_INT: |
| 606 | case TYPE_SHORT: |
| 607 | cls = env->FindClass("java/lang/Integer" ); |
| 608 | cns = env->GetMethodID(cls, "<init>" , "(I)V" ); |
| 609 | val = env->NewObject(cls, cns, valp->GetIntValue()); |
| 610 | break; |
| 611 | case TYPE_TINY: |
| 612 | cls = env->FindClass("java/lang/Boolean" ); |
| 613 | cns = env->GetMethodID(cls, "<init>" , "(Z)V" ); |
| 614 | val = env->NewObject(cls, cns, (valp->GetIntValue() != 0)); |
| 615 | break; |
| 616 | case TYPE_BIGINT: |
| 617 | cls = env->FindClass("java/lang/Long" ); |
| 618 | cns = env->GetMethodID(cls, "<init>" , "(J)V" ); |
| 619 | val = env->NewObject(cls, cns, valp->GetBigintValue()); |
| 620 | break; |
| 621 | case TYPE_DOUBLE: |
| 622 | cls = env->FindClass("java/lang/Double" ); |
| 623 | cns = env->GetMethodID(cls, "<init>" , "(D)V" ); |
| 624 | val = env->NewObject(cls, cns, valp->GetFloatValue()); |
| 625 | break; |
| 626 | default: |
| 627 | sprintf(g->Message, "Cannot make object from %d type" , valp->GetType()); |
| 628 | error = true; |
| 629 | break; |
| 630 | } // endswitch Type |
| 631 | |
| 632 | } catch (...) { |
| 633 | sprintf(g->Message, "Cannot make object from %s value" , colp->GetName()); |
| 634 | error = true; |
| 635 | } // end try/catch |
| 636 | |
| 637 | return val; |
| 638 | } // end of MakeObject |
| 639 | |
| 640 | /***********************************************************************/ |
| 641 | /* MakeDoc. */ |
| 642 | /***********************************************************************/ |
| 643 | jobject JMgoConn::MakeDoc(PGLOBAL g, PJNCOL jcp) |
| 644 | { |
| 645 | bool error = false; |
| 646 | jobject parent, child, val; |
| 647 | jstring jkey; |
| 648 | |
| 649 | if (jcp->Array) |
| 650 | parent = env->CallObjectMethod(job, mkarid); |
| 651 | else |
| 652 | parent = env->CallObjectMethod(job, mkdocid); |
| 653 | |
| 654 | for (PJKC kp = jcp->Klist; kp; kp = kp->Next) |
| 655 | if (kp->Jncolp) { |
| 656 | if (!(child = MakeDoc(g, kp->Jncolp))) |
| 657 | return NULL; |
| 658 | |
| 659 | if (!jcp->Array) { |
| 660 | jkey = env->NewStringUTF(kp->Key); |
| 661 | |
| 662 | if (env->CallBooleanMethod(job, docaddid, parent, jkey, child)) |
| 663 | return NULL; |
| 664 | |
| 665 | env->DeleteLocalRef(jkey); |
| 666 | } else |
| 667 | if (env->CallBooleanMethod(job, araddid, parent, kp->N, child)) |
| 668 | return NULL; |
| 669 | |
| 670 | } else { |
| 671 | if (!(val = MakeObject(g, kp->Colp, error))) { |
| 672 | if (error) |
| 673 | return NULL; |
| 674 | |
| 675 | } else if (!jcp->Array) { |
| 676 | jkey = env->NewStringUTF(kp->Key); |
| 677 | |
| 678 | if (env->CallBooleanMethod(job, docaddid, parent, jkey, val)) |
| 679 | return NULL; |
| 680 | |
| 681 | env->DeleteLocalRef(jkey); |
| 682 | } else if (env->CallBooleanMethod(job, araddid, parent, kp->N, val)) { |
| 683 | if (Check(-1)) |
| 684 | sprintf(g->Message, "ArrayAdd: %s" , Msg); |
| 685 | else |
| 686 | sprintf(g->Message, "ArrayAdd: unknown error" ); |
| 687 | |
| 688 | return NULL; |
| 689 | } // endif ArrayAdd |
| 690 | |
| 691 | } // endif Jncolp |
| 692 | |
| 693 | return parent; |
| 694 | } // end of MakeDoc |
| 695 | |
| 696 | /***********************************************************************/ |
| 697 | /* Insert a new document in the collation. */ |
| 698 | /***********************************************************************/ |
| 699 | int JMgoConn::DocWrite(PGLOBAL g) |
| 700 | { |
| 701 | jobject doc; |
| 702 | |
| 703 | if (!Fpc || !(doc = MakeDoc(g, Fpc))) |
| 704 | return RC_FX; |
| 705 | |
| 706 | if (env->CallBooleanMethod(job, insertid, doc)) { |
| 707 | if (Check(-1)) |
| 708 | sprintf(g->Message, "CollInsert: %s" , Msg); |
| 709 | else |
| 710 | sprintf(g->Message, "CollInsert: unknown error" ); |
| 711 | |
| 712 | return RC_FX; |
| 713 | } // endif Insert |
| 714 | |
| 715 | return RC_OK; |
| 716 | } // end of DocWrite |
| 717 | |
| 718 | /***********************************************************************/ |
| 719 | /* Update the current document from the collection. */ |
| 720 | /***********************************************************************/ |
| 721 | int JMgoConn::DocUpdate(PGLOBAL g, PTDB tdbp) |
| 722 | { |
| 723 | int rc = RC_OK; |
| 724 | bool error; |
| 725 | PCOL colp; |
| 726 | jstring jkey; |
| 727 | jobject val, upd, updlist = env->CallObjectMethod(job, mkdocid); |
| 728 | |
| 729 | // Make the list of changes to do |
| 730 | for (colp = tdbp->GetSetCols(); colp; colp = colp->GetNext()) { |
| 731 | jkey = env->NewStringUTF(colp->GetJpath(g, false)); |
| 732 | val = MakeObject(g, colp, error); |
| 733 | |
| 734 | if (error) |
| 735 | return RC_FX; |
| 736 | |
| 737 | if (env->CallBooleanMethod(job, docaddid, updlist, jkey, val)) |
| 738 | return RC_OK; |
| 739 | |
| 740 | env->DeleteLocalRef(jkey); |
| 741 | } // endfor colp |
| 742 | |
| 743 | // Make the update parameter |
| 744 | upd = env->CallObjectMethod(job, mkdocid); |
| 745 | jkey = env->NewStringUTF("$set" ); |
| 746 | |
| 747 | if (env->CallBooleanMethod(job, docaddid, upd, jkey, updlist)) |
| 748 | return RC_OK; |
| 749 | |
| 750 | env->DeleteLocalRef(jkey); |
| 751 | |
| 752 | jlong ar = env->CallLongMethod(job, updateid, upd); |
| 753 | |
| 754 | if (trace(1)) |
| 755 | htrc("DocUpdate: ar = %ld\n" , ar); |
| 756 | |
| 757 | if (Check((int)ar)) { |
| 758 | sprintf(g->Message, "CollUpdate: %s" , Msg); |
| 759 | rc = RC_FX; |
| 760 | } // endif ar |
| 761 | |
| 762 | return rc; |
| 763 | } // end of DocUpdate |
| 764 | |
| 765 | /***********************************************************************/ |
| 766 | /* Remove all or only the current document from the collection. */ |
| 767 | /***********************************************************************/ |
| 768 | int JMgoConn::DocDelete(PGLOBAL g, bool all) |
| 769 | { |
| 770 | int rc = RC_OK; |
| 771 | jlong ar = env->CallLongMethod(job, deleteid, all); |
| 772 | |
| 773 | if (trace(1)) |
| 774 | htrc("DocDelete: ar = %ld\n" , ar); |
| 775 | |
| 776 | if (Check((int)ar)) { |
| 777 | sprintf(g->Message, "CollDelete: %s" , Msg); |
| 778 | rc = RC_FX; |
| 779 | } // endif ar |
| 780 | |
| 781 | return rc; |
| 782 | } // end of DocDelete |
| 783 | |
| 784 | /***********************************************************************/ |
| 785 | /* Rewind the collection. */ |
| 786 | /***********************************************************************/ |
| 787 | bool JMgoConn::Rewind(void) |
| 788 | { |
| 789 | return env->CallBooleanMethod(job, rewindid); |
| 790 | } // end of Rewind |
| 791 | |
| 792 | /***********************************************************************/ |
| 793 | /* Retrieve the column string value from the document. */ |
| 794 | /***********************************************************************/ |
| 795 | PSZ JMgoConn::GetColumnValue(PSZ path) |
| 796 | { |
| 797 | PGLOBAL& g = m_G; |
| 798 | PSZ fld = NULL; |
| 799 | jstring fn, jn = nullptr; |
| 800 | |
| 801 | if (!path || (jn = env->NewStringUTF(path)) == nullptr) { |
| 802 | sprintf(g->Message, "Fail to allocate jstring %s" , SVP(path)); |
| 803 | throw (int)TYPE_AM_MGO; |
| 804 | } // endif name |
| 805 | |
| 806 | if (!gmID(g, objfldid, "GetField" , "(Ljava/lang/String;)Ljava/lang/String;" )) { |
| 807 | fn = (jstring)env->CallObjectMethod(job, objfldid, jn); |
| 808 | |
| 809 | if (fn) |
| 810 | fld = (PSZ)env->GetStringUTFChars(fn, (jboolean)false); |
| 811 | |
| 812 | } // endif objfldid |
| 813 | |
| 814 | return fld; |
| 815 | } // end of GetColumnValue |
| 816 | |