| 1 | /************* TabJDBC C++ Program Source Code File (.CPP) *************/ |
| 2 | /* PROGRAM NAME: TABJDBC */ |
| 3 | /* ------------- */ |
| 4 | /* Version 1.2 */ |
| 5 | /* */ |
| 6 | /* COPYRIGHT: */ |
| 7 | /* ---------- */ |
| 8 | /* (C) Copyright to the author Olivier BERTRAND 2016-2017 */ |
| 9 | /* */ |
| 10 | /* WHAT THIS PROGRAM DOES: */ |
| 11 | /* ----------------------- */ |
| 12 | /* This program are the TABJDBC class DB execution routines. */ |
| 13 | /* */ |
| 14 | /* WHAT YOU NEED TO COMPILE THIS PROGRAM: */ |
| 15 | /* -------------------------------------- */ |
| 16 | /* */ |
| 17 | /* REQUIRED FILES: */ |
| 18 | /* --------------- */ |
| 19 | /* TABJDBC.CPP - Source code */ |
| 20 | /* PLGDBSEM.H - DB application declaration file */ |
| 21 | /* TABJDBC.H - TABJDBC classes declaration file */ |
| 22 | /* GLOBAL.H - Global declaration file */ |
| 23 | /* */ |
| 24 | /* REQUIRED LIBRARIES: */ |
| 25 | /* ------------------- */ |
| 26 | /* Large model C library */ |
| 27 | /* */ |
| 28 | /* REQUIRED PROGRAMS: */ |
| 29 | /* ------------------ */ |
| 30 | /* IBM, Borland, GNU or Microsoft C++ Compiler and Linker */ |
| 31 | /* */ |
| 32 | /***********************************************************************/ |
| 33 | |
| 34 | /***********************************************************************/ |
| 35 | /* Include relevant MariaDB header file. */ |
| 36 | /***********************************************************************/ |
| 37 | #define MYSQL_SERVER 1 |
| 38 | #include "my_global.h" |
| 39 | #include "sql_class.h" |
| 40 | #include "sql_servers.h" |
| 41 | #if defined(__WIN__) |
| 42 | #include <io.h> |
| 43 | #include <fcntl.h> |
| 44 | #if defined(__BORLANDC__) |
| 45 | #define __MFC_COMPAT__ // To define min/max as macro |
| 46 | #endif |
| 47 | //#include <windows.h> |
| 48 | #include <sqltypes.h> |
| 49 | #else |
| 50 | #if defined(UNIX) |
| 51 | #include <errno.h> |
| 52 | #define NODW |
| 53 | #include "osutil.h" |
| 54 | #else |
| 55 | #include <io.h> |
| 56 | #endif |
| 57 | #include <fcntl.h> |
| 58 | #endif |
| 59 | |
| 60 | /***********************************************************************/ |
| 61 | /* Include application header files: */ |
| 62 | /* global.h is header containing all global declarations. */ |
| 63 | /* plgdbsem.h is header containing the DB application declarations. */ |
| 64 | /* kindex.h is kindex header that also includes tabdos.h. */ |
| 65 | /* tabJDBC.h is header containing the TABJDBC class declarations. */ |
| 66 | /* JDBConn.h is header containing JDBC connection declarations. */ |
| 67 | /***********************************************************************/ |
| 68 | #include "global.h" |
| 69 | #include "plgdbsem.h" |
| 70 | #include "mycat.h" |
| 71 | #include "xtable.h" |
| 72 | #include "tabext.h" |
| 73 | #include "tabjdbc.h" |
| 74 | #include "tabmul.h" |
| 75 | //#include "reldef.h" |
| 76 | #include "tabcol.h" |
| 77 | #include "valblk.h" |
| 78 | #include "ha_connect.h" |
| 79 | |
| 80 | #include "sql_string.h" |
| 81 | |
| 82 | /***********************************************************************/ |
| 83 | /* DB static variables. */ |
| 84 | /***********************************************************************/ |
| 85 | // int num_read, num_there, num_eq[2], num_nf; // Statistics |
| 86 | extern int num_read, num_there, num_eq[2]; // Statistics |
| 87 | |
| 88 | /***********************************************************************/ |
| 89 | /* External function. */ |
| 90 | /***********************************************************************/ |
| 91 | bool ExactInfo(void); |
| 92 | |
| 93 | /* -------------------------- Class JDBCDEF -------------------------- */ |
| 94 | |
| 95 | /***********************************************************************/ |
| 96 | /* Constructor. */ |
| 97 | /***********************************************************************/ |
| 98 | JDBCDEF::JDBCDEF(void) |
| 99 | { |
| 100 | Driver = Url = Wrapname = NULL; |
| 101 | } // end of JDBCDEF constructor |
| 102 | |
| 103 | /***********************************************************************/ |
| 104 | /* Called on table construction. */ |
| 105 | /***********************************************************************/ |
| 106 | bool JDBCDEF::SetParms(PJPARM sjp) |
| 107 | { |
| 108 | sjp->Url= Url; |
| 109 | sjp->User= Username; |
| 110 | sjp->Pwd= Password; |
| 111 | //sjp->Properties = Prop; |
| 112 | return true; |
| 113 | } // end of SetParms |
| 114 | |
| 115 | /***********************************************************************/ |
| 116 | /* Parse connection string */ |
| 117 | /* */ |
| 118 | /* SYNOPSIS */ |
| 119 | /* ParseURL() */ |
| 120 | /* Url The connection string to parse */ |
| 121 | /* */ |
| 122 | /* DESCRIPTION */ |
| 123 | /* This is used to set the Url in case a wrapper server as been */ |
| 124 | /* specified. This is rather experimental yet. */ |
| 125 | /* */ |
| 126 | /* RETURN VALUE */ |
| 127 | /* RC_OK Url was a true URL */ |
| 128 | /* RC_NF Url was a server name/table */ |
| 129 | /* RC_FX Error */ |
| 130 | /* */ |
| 131 | /***********************************************************************/ |
| 132 | int JDBCDEF::ParseURL(PGLOBAL g, char *url, bool b) |
| 133 | { |
| 134 | if (strncmp(url, "jdbc:" , 5)) { |
| 135 | PSZ p; |
| 136 | |
| 137 | // No "jdbc:" in connection string. Must be a straight |
| 138 | // "server" or "server/table" |
| 139 | // ok, so we do a little parsing, but not completely! |
| 140 | if ((p = strchr(url, '/'))) { |
| 141 | // If there is a single '/' in the connection string, |
| 142 | // this means the user is specifying a table name |
| 143 | *p++= '\0'; |
| 144 | |
| 145 | // there better not be any more '/'s ! |
| 146 | if (strchr(p, '/')) |
| 147 | return RC_FX; |
| 148 | |
| 149 | Tabname = p; |
| 150 | // } else if (b) { |
| 151 | // // Otherwise, straight server name, |
| 152 | // Tabname = GetStringCatInfo(g, "Name", NULL); |
| 153 | // Tabname = GetStringCatInfo(g, "Tabname", Tabname); |
| 154 | } // endif |
| 155 | |
| 156 | if (trace(1)) |
| 157 | htrc("server: %s Tabname: %s" , url, Tabname); |
| 158 | |
| 159 | // Now make the required URL |
| 160 | FOREIGN_SERVER *server, server_buffer; |
| 161 | |
| 162 | // get_server_by_name() clones the server if exists |
| 163 | if (!(server= get_server_by_name(current_thd->mem_root, url, &server_buffer))) { |
| 164 | sprintf(g->Message, "Server %s does not exist!" , url); |
| 165 | return RC_FX; |
| 166 | } // endif server |
| 167 | |
| 168 | if (strncmp(server->host, "jdbc:" , 5)) { |
| 169 | // Now make the required URL |
| 170 | Url = (PSZ)PlugSubAlloc(g, NULL, 0); |
| 171 | strcat(strcpy(Url, "jdbc:" ), server->scheme); |
| 172 | strcat(strcat(Url, "://" ), server->host); |
| 173 | |
| 174 | if (server->port) { |
| 175 | char buf[16]; |
| 176 | |
| 177 | sprintf(buf, "%ld" , server->port); |
| 178 | strcat(strcat(Url, ":" ), buf); |
| 179 | } // endif port |
| 180 | |
| 181 | if (server->db) |
| 182 | strcat(strcat(Url, "/" ), server->db); |
| 183 | |
| 184 | PlugSubAlloc(g, NULL, strlen(Url) + 1); |
| 185 | } else // host is a URL |
| 186 | Url = PlugDup(g, server->host); |
| 187 | |
| 188 | if (server->username) |
| 189 | Username = PlugDup(g, server->username); |
| 190 | |
| 191 | if (server->password) |
| 192 | Password = PlugDup(g, server->password); |
| 193 | |
| 194 | return RC_NF; |
| 195 | } // endif |
| 196 | |
| 197 | // Url was a JDBC URL, nothing to do |
| 198 | return RC_OK; |
| 199 | } // end of ParseURL |
| 200 | |
| 201 | /***********************************************************************/ |
| 202 | /* DefineAM: define specific AM block values from JDBC file. */ |
| 203 | /***********************************************************************/ |
| 204 | bool JDBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff) |
| 205 | { |
| 206 | int rc = RC_OK; |
| 207 | |
| 208 | if (EXTDEF::DefineAM(g, am, poff)) |
| 209 | return true; |
| 210 | |
| 211 | Driver = GetStringCatInfo(g, "Driver" , NULL); |
| 212 | Desc = Url = GetStringCatInfo(g, "Connect" , NULL); |
| 213 | |
| 214 | if (!Url && !Catfunc) { |
| 215 | // Look in the option list (deprecated) |
| 216 | Url = GetStringCatInfo(g, "Url" , NULL); |
| 217 | |
| 218 | if (!Url) { |
| 219 | sprintf(g->Message, "Missing URL for JDBC table %s" , Name); |
| 220 | return true; |
| 221 | } // endif Url |
| 222 | |
| 223 | } // endif Connect |
| 224 | |
| 225 | if (Url) |
| 226 | if ((rc = ParseURL(g, Url)) == RC_FX) { |
| 227 | sprintf(g->Message, "Wrong JDBC URL %s" , Url); |
| 228 | return true; |
| 229 | } // endif rc |
| 230 | |
| 231 | Wrapname = GetStringCatInfo(g, "Wrapper" , NULL); |
| 232 | return false; |
| 233 | } // end of DefineAM |
| 234 | |
| 235 | /***********************************************************************/ |
| 236 | /* GetTable: makes a new Table Description Block. */ |
| 237 | /***********************************************************************/ |
| 238 | PTDB JDBCDEF::GetTable(PGLOBAL g, MODE m) |
| 239 | { |
| 240 | PTDB tdbp = NULL; |
| 241 | |
| 242 | /*********************************************************************/ |
| 243 | /* Allocate a TDB of the proper type. */ |
| 244 | /* Column blocks will be allocated only when needed. */ |
| 245 | /*********************************************************************/ |
| 246 | if (Xsrc) |
| 247 | tdbp = new(g)TDBXJDC(this); |
| 248 | else switch (Catfunc) { |
| 249 | case FNC_COL: |
| 250 | tdbp = new(g)TDBJDBCL(this); |
| 251 | break; |
| 252 | #if 0 |
| 253 | case FNC_DSN: |
| 254 | tdbp = new(g)TDBJSRC(this); |
| 255 | break; |
| 256 | #endif // 0 |
| 257 | case FNC_TABLE: |
| 258 | tdbp = new(g)TDBJTB(this); |
| 259 | break; |
| 260 | case FNC_DRIVER: |
| 261 | tdbp = new(g)TDBJDRV(this); |
| 262 | break; |
| 263 | default: |
| 264 | tdbp = new(g)TDBJDBC(this); |
| 265 | |
| 266 | if (Multiple == 1) |
| 267 | tdbp = new(g)TDBMUL(tdbp); |
| 268 | else if (Multiple == 2) |
| 269 | strcpy(g->Message, "NO_JDBC_MUL" ); |
| 270 | |
| 271 | } // endswitch Catfunc |
| 272 | |
| 273 | return tdbp; |
| 274 | } // end of GetTable |
| 275 | |
| 276 | /***********************************************************************/ |
| 277 | /* The MySQL and MariaDB JDBC drivers return by default a result set */ |
| 278 | /* containing the entire result of the executed query. This can be an */ |
| 279 | /* issue for big tables and memory error can occur. An alternative is */ |
| 280 | /* to use streaming (reading one row at a time) but to specify this, */ |
| 281 | /* a fech size of the integer min value must be send to the driver. */ |
| 282 | /***********************************************************************/ |
| 283 | int JDBCPARM::CheckSize(int rows) |
| 284 | { |
| 285 | if (Url && rows == 1) { |
| 286 | // Are we connected to a MySQL JDBC connector? |
| 287 | bool b = (!strncmp(Url, "jdbc:mysql:" , 11) || |
| 288 | !strncmp(Url, "jdbc:mariadb:" , 13)); |
| 289 | return b ? INT_MIN32 : rows; |
| 290 | } else |
| 291 | return rows; |
| 292 | |
| 293 | } // end of CheckSize |
| 294 | |
| 295 | /* -------------------------- Class TDBJDBC -------------------------- */ |
| 296 | |
| 297 | /***********************************************************************/ |
| 298 | /* Implementation of the TDBJDBC class. */ |
| 299 | /***********************************************************************/ |
| 300 | TDBJDBC::TDBJDBC(PJDBCDEF tdp) : TDBEXT(tdp) |
| 301 | { |
| 302 | Jcp = NULL; |
| 303 | Cnp = NULL; |
| 304 | |
| 305 | if (tdp) { |
| 306 | Ops.Driver = tdp->Driver; |
| 307 | Ops.Url = tdp->Url; |
| 308 | Wrapname = tdp->Wrapname; |
| 309 | Ops.User = tdp->Username; |
| 310 | Ops.Pwd = tdp->Password; |
| 311 | Ops.Scrollable = tdp->Scrollable; |
| 312 | } else { |
| 313 | Wrapname = NULL; |
| 314 | Ops.Driver = NULL; |
| 315 | Ops.Url = NULL; |
| 316 | Ops.User = NULL; |
| 317 | Ops.Pwd = NULL; |
| 318 | Ops.Scrollable = false; |
| 319 | } // endif tdp |
| 320 | |
| 321 | Prepared = false; |
| 322 | Werr = false; |
| 323 | Rerr = false; |
| 324 | Ops.Fsize = Ops.CheckSize(Rows); |
| 325 | } // end of TDBJDBC standard constructor |
| 326 | |
| 327 | TDBJDBC::TDBJDBC(PTDBJDBC tdbp) : TDBEXT(tdbp) |
| 328 | { |
| 329 | Jcp = tdbp->Jcp; // is that right ? |
| 330 | Cnp = tdbp->Cnp; |
| 331 | Wrapname = tdbp->Wrapname; |
| 332 | Ops = tdbp->Ops; |
| 333 | Prepared = tdbp->Prepared; |
| 334 | Werr = tdbp->Werr; |
| 335 | Rerr = tdbp->Rerr; |
| 336 | } // end of TDBJDBC copy constructor |
| 337 | |
| 338 | // Method |
| 339 | PTDB TDBJDBC::Clone(PTABS t) |
| 340 | { |
| 341 | PTDB tp; |
| 342 | PJDBCCOL cp1, cp2; |
| 343 | PGLOBAL g = t->G; // Is this really useful ??? |
| 344 | |
| 345 | tp = new(g)TDBJDBC(this); |
| 346 | |
| 347 | for (cp1 = (PJDBCCOL)Columns; cp1; cp1 = (PJDBCCOL)cp1->GetNext()) { |
| 348 | cp2 = new(g)JDBCCOL(cp1, tp); // Make a copy |
| 349 | NewPointer(t, cp1, cp2); |
| 350 | } // endfor cp1 |
| 351 | |
| 352 | return tp; |
| 353 | } // end of Clone |
| 354 | |
| 355 | /***********************************************************************/ |
| 356 | /* Allocate JDBC column description block. */ |
| 357 | /***********************************************************************/ |
| 358 | PCOL TDBJDBC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) |
| 359 | { |
| 360 | return new(g)JDBCCOL(cdp, this, cprec, n); |
| 361 | } // end of MakeCol |
| 362 | |
| 363 | /***********************************************************************/ |
| 364 | /* MakeInsert: make the Insert statement used with JDBC connection. */ |
| 365 | /***********************************************************************/ |
| 366 | bool TDBJDBC::MakeInsert(PGLOBAL g) |
| 367 | { |
| 368 | PCSZ schmp = NULL; |
| 369 | char *catp = NULL, buf[NAM_LEN * 3]; |
| 370 | int len = 0; |
| 371 | uint pos; |
| 372 | bool b = false; |
| 373 | PTABLE tablep = To_Table; |
| 374 | PCOL colp; |
| 375 | |
| 376 | for (colp = Columns; colp; colp = colp->GetNext()) |
| 377 | if (colp->IsSpecial()) { |
| 378 | strcpy(g->Message, "No JDBC special columns" ); |
| 379 | return true; |
| 380 | } else { |
| 381 | // Column name can be encoded in UTF-8 |
| 382 | Decode(colp->GetName(), buf, sizeof(buf)); |
| 383 | len += (strlen(buf) + 6); // comma + quotes + valist |
| 384 | ((PEXTCOL)colp)->SetRank(++Nparm); |
| 385 | } // endif colp |
| 386 | |
| 387 | // Below 32 is enough to contain the fixed part of the query |
| 388 | if (Catalog && *Catalog) |
| 389 | catp = Catalog; |
| 390 | |
| 391 | if (catp) |
| 392 | len += strlen(catp) + 1; |
| 393 | |
| 394 | //if (tablep->GetSchema()) |
| 395 | // schmp = (char*)tablep->GetSchema(); |
| 396 | //else |
| 397 | if (Schema && *Schema) |
| 398 | schmp = Schema; |
| 399 | |
| 400 | if (schmp) |
| 401 | len += strlen(schmp) + 1; |
| 402 | |
| 403 | // Table name can be encoded in UTF-8 |
| 404 | Decode(TableName, buf, sizeof(buf)); |
| 405 | len += (strlen(buf) + 32); |
| 406 | Query = new(g)STRING(g, len, "INSERT INTO " ); |
| 407 | |
| 408 | if (catp) { |
| 409 | Query->Append(catp); |
| 410 | |
| 411 | if (schmp) { |
| 412 | Query->Append('.'); |
| 413 | Query->Append(schmp); |
| 414 | } // endif schmp |
| 415 | |
| 416 | Query->Append('.'); |
| 417 | } else if (schmp) { |
| 418 | Query->Append(schmp); |
| 419 | Query->Append('.'); |
| 420 | } // endif schmp |
| 421 | |
| 422 | if (Quote) { |
| 423 | // Put table name between identifier quotes in case in contains blanks |
| 424 | Query->Append(Quote); |
| 425 | Query->Append(buf); |
| 426 | Query->Append(Quote); |
| 427 | } else |
| 428 | Query->Append(buf); |
| 429 | |
| 430 | Query->Append('('); |
| 431 | |
| 432 | for (colp = Columns; colp; colp = colp->GetNext()) { |
| 433 | if (b) |
| 434 | Query->Append(", " ); |
| 435 | else |
| 436 | b = true; |
| 437 | |
| 438 | // Column name can be in UTF-8 encoding |
| 439 | Decode(colp->GetName(), buf, sizeof(buf)); |
| 440 | |
| 441 | if (Quote) { |
| 442 | // Put column name between identifier quotes in case in contains blanks |
| 443 | Query->Append(Quote); |
| 444 | Query->Append(buf); |
| 445 | Query->Append(Quote); |
| 446 | } else |
| 447 | Query->Append(buf); |
| 448 | |
| 449 | } // endfor colp |
| 450 | |
| 451 | if ((Query->Append(") VALUES (" ))) { |
| 452 | strcpy(g->Message, "MakeInsert: Out of memory" ); |
| 453 | return true; |
| 454 | } else // in case prepared statement fails |
| 455 | pos = Query->GetLength(); |
| 456 | |
| 457 | // Make prepared statement |
| 458 | for (int i = 0; i < Nparm; i++) |
| 459 | Query->Append("?," ); |
| 460 | |
| 461 | if (Query->IsTruncated()) { |
| 462 | strcpy(g->Message, "MakeInsert: Out of memory" ); |
| 463 | return true; |
| 464 | } else |
| 465 | Query->RepLast(')'); |
| 466 | |
| 467 | // Now see if we can use prepared statement |
| 468 | if (Jcp->PrepareSQL(Query->GetStr())) |
| 469 | Query->Truncate(pos); // Restore query to not prepared |
| 470 | else |
| 471 | Prepared = true; |
| 472 | |
| 473 | if (trace(33)) |
| 474 | htrc("Insert=%s\n" , Query->GetStr()); |
| 475 | |
| 476 | return false; |
| 477 | } // end of MakeInsert |
| 478 | |
| 479 | /***********************************************************************/ |
| 480 | /* JDBC Set Parameter function. */ |
| 481 | /***********************************************************************/ |
| 482 | bool TDBJDBC::SetParameters(PGLOBAL g) |
| 483 | { |
| 484 | PJDBCCOL colp; |
| 485 | |
| 486 | for (colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->Next) |
| 487 | if (Jcp->SetParam(colp)) |
| 488 | return true; |
| 489 | |
| 490 | return false; |
| 491 | } // end of SetParameters |
| 492 | |
| 493 | /***********************************************************************/ |
| 494 | /* ResetSize: call by TDBMUL when calculating size estimate. */ |
| 495 | /***********************************************************************/ |
| 496 | void TDBJDBC::ResetSize(void) |
| 497 | { |
| 498 | MaxSize = -1; |
| 499 | |
| 500 | if (Jcp && Jcp->IsOpen()) |
| 501 | Jcp->Close(); |
| 502 | |
| 503 | } // end of ResetSize |
| 504 | |
| 505 | /***********************************************************************/ |
| 506 | /* JDBC Cardinality: returns table size in number of rows. */ |
| 507 | /***********************************************************************/ |
| 508 | int TDBJDBC::Cardinality(PGLOBAL g) |
| 509 | { |
| 510 | if (!g) |
| 511 | return (Mode == MODE_ANY && !Srcdef) ? 1 : 0; |
| 512 | |
| 513 | #if 0 |
| 514 | if (Cardinal < 0 && Mode == MODE_ANY && !Srcdef && ExactInfo()) { |
| 515 | // Info command, we must return the exact table row number |
| 516 | char qry[96], tbn[64]; |
| 517 | JDBConn *jcp = new(g)JDBConn(g, this); |
| 518 | |
| 519 | if (jcp->Open(&Ops) == RC_FX) |
| 520 | return -1; |
| 521 | |
| 522 | // Table name can be encoded in UTF-8 |
| 523 | Decode(TableName, tbn, sizeof(tbn)); |
| 524 | strcpy(qry, "SELECT COUNT(*) FROM " ); |
| 525 | |
| 526 | if (Quote) |
| 527 | strcat(strcat(strcat(qry, Quote), tbn), Quote); |
| 528 | else |
| 529 | strcat(qry, tbn); |
| 530 | |
| 531 | // Allocate a Count(*) column (must not use the default constructor) |
| 532 | Cnp = new(g)JDBCCOL; |
| 533 | Cnp->InitValue(g); |
| 534 | |
| 535 | if ((Cardinal = jcp->GetResultSize(qry, Cnp)) < 0) |
| 536 | return -3; |
| 537 | |
| 538 | jcp->Close(); |
| 539 | } else |
| 540 | #endif // 0 |
| 541 | Cardinal = 10; // To make MariaDB happy |
| 542 | |
| 543 | return Cardinal; |
| 544 | } // end of Cardinality |
| 545 | |
| 546 | /***********************************************************************/ |
| 547 | /* JDBC Access Method opening routine. */ |
| 548 | /* New method now that this routine is called recursively (last table */ |
| 549 | /* first in reverse order): index blocks are immediately linked to */ |
| 550 | /* join block of next table if it exists or else are discarted. */ |
| 551 | /***********************************************************************/ |
| 552 | bool TDBJDBC::OpenDB(PGLOBAL g) |
| 553 | { |
| 554 | bool rc = true; |
| 555 | |
| 556 | if (trace(1)) |
| 557 | htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n" , |
| 558 | this, Tdb_No, Use, Mode); |
| 559 | |
| 560 | if (Use == USE_OPEN) { |
| 561 | /*******************************************************************/ |
| 562 | /* Table already open, just replace it at its beginning. */ |
| 563 | /*******************************************************************/ |
| 564 | if (Memory == 1) { |
| 565 | if ((Qrp = Jcp->AllocateResult(g, this))) |
| 566 | Memory = 2; // Must be filled |
| 567 | else |
| 568 | Memory = 0; // Allocation failed, don't use it |
| 569 | |
| 570 | } else if (Memory == 2) |
| 571 | Memory = 3; // Ok to use memory result |
| 572 | |
| 573 | if (Memory < 3) { |
| 574 | // Method will depend on cursor type |
| 575 | if ((Rbuf = Query ? Jcp->Rewind(Query->GetStr()) : 0) < 0) |
| 576 | if (Mode != MODE_READX) { |
| 577 | Jcp->Close(); |
| 578 | return true; |
| 579 | } else |
| 580 | Rbuf = 0; |
| 581 | |
| 582 | } else |
| 583 | Rbuf = Qrp->Nblin; |
| 584 | |
| 585 | CurNum = 0; |
| 586 | Fpos = 0; |
| 587 | Curpos = 1; |
| 588 | return false; |
| 589 | } // endif use |
| 590 | |
| 591 | /*********************************************************************/ |
| 592 | /* Open an JDBC connection for this table. */ |
| 593 | /* Note: this may not be the proper way to do. Perhaps it is better */ |
| 594 | /* to test whether a connection is already open for this datasource */ |
| 595 | /* and if so to allocate just a new result set. But this only for */ |
| 596 | /* drivers allowing concurency in getting results ??? */ |
| 597 | /*********************************************************************/ |
| 598 | if (!Jcp) |
| 599 | Jcp = new(g)JDBConn(g, Wrapname); |
| 600 | else if (Jcp->IsOpen()) |
| 601 | Jcp->Close(); |
| 602 | |
| 603 | if (Jcp->Connect(&Ops)) |
| 604 | return true; |
| 605 | else if (Quoted) |
| 606 | Quote = Jcp->GetQuoteChar(); |
| 607 | |
| 608 | if (Mode != MODE_READ && Mode != MODE_READX) |
| 609 | if (Jcp->SetUUID(g, this)) |
| 610 | PushWarning(g, this, 1); |
| 611 | |
| 612 | Use = USE_OPEN; // Do it now in case we are recursively called |
| 613 | |
| 614 | /*********************************************************************/ |
| 615 | /* Make the command and allocate whatever is used for getting results*/ |
| 616 | /*********************************************************************/ |
| 617 | if (Mode == MODE_READ || Mode == MODE_READX) { |
| 618 | if (Memory > 1 && !Srcdef) { |
| 619 | int n; |
| 620 | |
| 621 | if (!MakeSQL(g, true)) { |
| 622 | // Allocate a Count(*) column |
| 623 | Cnp = new(g)JDBCCOL; |
| 624 | Cnp->InitValue(g); |
| 625 | |
| 626 | if ((n = Jcp->GetResultSize(Query->GetStr(), Cnp)) < 0) { |
| 627 | sprintf(g->Message, "Cannot get result size rc=%d" , n); |
| 628 | return true; |
| 629 | } else if (n) { |
| 630 | Jcp->m_Rows = n; |
| 631 | |
| 632 | if ((Qrp = Jcp->AllocateResult(g, this))) |
| 633 | Memory = 2; // Must be filled |
| 634 | else { |
| 635 | strcpy(g->Message, "Result set memory allocation failed" ); |
| 636 | return true; |
| 637 | } // endif n |
| 638 | |
| 639 | } else // Void result |
| 640 | Memory = 0; |
| 641 | |
| 642 | Jcp->m_Rows = 0; |
| 643 | } else |
| 644 | return true; |
| 645 | |
| 646 | } // endif Memory |
| 647 | |
| 648 | if (!(rc = MakeSQL(g, false))) { |
| 649 | // for (PJDBCCOL colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->GetNext()) |
| 650 | // if (!colp->IsSpecial()) |
| 651 | // colp->AllocateBuffers(g, Rows); |
| 652 | |
| 653 | rc = (Mode == MODE_READ) |
| 654 | ? (Jcp->ExecuteQuery(Query->GetStr()) != RC_OK) |
| 655 | : false; |
| 656 | } // endif rc |
| 657 | |
| 658 | } else if (Mode == MODE_INSERT) { |
| 659 | #if 0 |
| 660 | if (!(rc = MakeInsert(g))) { |
| 661 | if (Nparm != Jcp->PrepareSQL(Query->GetStr())) { |
| 662 | strcpy(g->Message, MSG(PARM_CNT_MISS)); |
| 663 | rc = true; |
| 664 | } else |
| 665 | rc = BindParameters(g); |
| 666 | |
| 667 | } // endif rc |
| 668 | #endif // 0 |
| 669 | rc = MakeInsert(g); |
| 670 | } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) { |
| 671 | rc = false; // wait for CheckCond before calling MakeCommand(g); |
| 672 | } else |
| 673 | sprintf(g->Message, "Invalid mode %d" , Mode); |
| 674 | |
| 675 | if (rc) { |
| 676 | Jcp->Close(); |
| 677 | return true; |
| 678 | } // endif rc |
| 679 | |
| 680 | /*********************************************************************/ |
| 681 | /* Reset statistics values. */ |
| 682 | /*********************************************************************/ |
| 683 | num_read = num_there = num_eq[0] = num_eq[1] = 0; |
| 684 | return false; |
| 685 | } // end of OpenDB |
| 686 | |
| 687 | #if 0 |
| 688 | /***********************************************************************/ |
| 689 | /* GetRecpos: return the position of last read record. */ |
| 690 | /***********************************************************************/ |
| 691 | int TDBJDBC::GetRecpos(void) |
| 692 | { |
| 693 | return Fpos; |
| 694 | } // end of GetRecpos |
| 695 | #endif // 0 |
| 696 | |
| 697 | /***********************************************************************/ |
| 698 | /* SetRecpos: set the position of next read record. */ |
| 699 | /***********************************************************************/ |
| 700 | bool TDBJDBC::SetRecpos(PGLOBAL g, int recpos) |
| 701 | { |
| 702 | if (Jcp->m_Full) { |
| 703 | Fpos = 0; |
| 704 | CurNum = 1; |
| 705 | } else if (Memory == 3) { |
| 706 | Fpos = 0; |
| 707 | CurNum = recpos; |
| 708 | } else if (Ops.Scrollable) { |
| 709 | // Is new position in the current row set? |
| 710 | if (recpos > 0 && recpos <= Rbuf) { |
| 711 | CurNum = recpos; |
| 712 | Fpos = recpos; |
| 713 | } else { |
| 714 | strcpy(g->Message, "Scrolling out of row set NIY" ); |
| 715 | return true; |
| 716 | } // endif recpos |
| 717 | |
| 718 | } else { |
| 719 | strcpy(g->Message, "This action requires a scrollable cursor" ); |
| 720 | return true; |
| 721 | } // endif's |
| 722 | |
| 723 | // Indicate the table position was externally set |
| 724 | Placed = true; |
| 725 | return false; |
| 726 | } // end of SetRecpos |
| 727 | |
| 728 | /***********************************************************************/ |
| 729 | /* Data Base indexed read routine for JDBC access method. */ |
| 730 | /***********************************************************************/ |
| 731 | bool TDBJDBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr) |
| 732 | { |
| 733 | char c = Quote ? *Quote : 0; |
| 734 | int rc, oldlen = Query->GetLength(); |
| 735 | PHC hc = To_Def->GetHandler(); |
| 736 | |
| 737 | if (!(kr || hc->end_range) || op == OP_NEXT || |
| 738 | Mode == MODE_UPDATE || Mode == MODE_DELETE) { |
| 739 | if (!kr && Mode == MODE_READX) { |
| 740 | // This is a false indexed read |
| 741 | rc = Jcp->ExecuteQuery((char*)Query->GetStr()); |
| 742 | Mode = MODE_READ; |
| 743 | Rows = 1; // ??? |
| 744 | return (rc != RC_OK); |
| 745 | } // endif key |
| 746 | |
| 747 | return false; |
| 748 | } else { |
| 749 | if (hc->MakeKeyWhere(g, Query, op, c, kr)) |
| 750 | return true; |
| 751 | |
| 752 | if (To_CondFil) { |
| 753 | if (To_CondFil->Idx != hc->active_index) { |
| 754 | To_CondFil->Idx = hc->active_index; |
| 755 | To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0); |
| 756 | *To_CondFil->Body= 0; |
| 757 | |
| 758 | if ((To_CondFil = hc->CheckCond(g, To_CondFil, Cond))) |
| 759 | PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1); |
| 760 | |
| 761 | } // endif active_index |
| 762 | |
| 763 | if (To_CondFil) |
| 764 | if (Query->Append(" AND " ) || Query->Append(To_CondFil->Body)) { |
| 765 | strcpy(g->Message, "Readkey: Out of memory" ); |
| 766 | return true; |
| 767 | } // endif Append |
| 768 | |
| 769 | } // endif To_Condfil |
| 770 | |
| 771 | Mode = MODE_READ; |
| 772 | } // endif's op |
| 773 | |
| 774 | if (trace(33)) |
| 775 | htrc("JDBC ReadKey: Query=%s\n" , Query->GetStr()); |
| 776 | |
| 777 | rc = Jcp->ExecuteQuery((char*)Query->GetStr()); |
| 778 | Query->Truncate(oldlen); |
| 779 | Rows = 1; // ??? |
| 780 | return (rc != RC_OK); |
| 781 | } // end of ReadKey |
| 782 | |
| 783 | /***********************************************************************/ |
| 784 | /* Data Base read routine for JDBC access method. */ |
| 785 | /***********************************************************************/ |
| 786 | int TDBJDBC::ReadDB(PGLOBAL g) |
| 787 | { |
| 788 | int rc; |
| 789 | |
| 790 | if (trace(2)) |
| 791 | htrc("JDBC ReadDB: R%d Mode=%d\n" , GetTdb_No(), Mode); |
| 792 | |
| 793 | if (Mode == MODE_UPDATE || Mode == MODE_DELETE) { |
| 794 | if (!Query && MakeCommand(g)) |
| 795 | return RC_FX; |
| 796 | |
| 797 | // Send the UPDATE/DELETE command to the remote table |
| 798 | rc = Jcp->ExecuteUpdate(Query->GetStr()); |
| 799 | |
| 800 | if (rc == RC_OK) { |
| 801 | AftRows = Jcp->m_Aff; |
| 802 | return RC_EF; // Nothing else to do |
| 803 | } else { |
| 804 | Werr = true; |
| 805 | return RC_FX; |
| 806 | } // endif rc |
| 807 | |
| 808 | } // endif Mode |
| 809 | |
| 810 | /*********************************************************************/ |
| 811 | /* Now start the reading process. */ |
| 812 | /* Here is the place to fetch the line(s). */ |
| 813 | /*********************************************************************/ |
| 814 | if (Placed) { |
| 815 | if (Fpos && CurNum >= 0) |
| 816 | Rbuf = Jcp->Fetch((Curpos = Fpos)); |
| 817 | else |
| 818 | Fpos = CurNum; |
| 819 | |
| 820 | rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX; |
| 821 | Placed = false; |
| 822 | } else { |
| 823 | if (Memory != 3) { |
| 824 | if (++CurNum >= Rbuf) { |
| 825 | Rbuf = Jcp->Fetch(); |
| 826 | Curpos = Fpos + 1; |
| 827 | CurNum = 0; |
| 828 | } // endif CurNum |
| 829 | |
| 830 | rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX; |
| 831 | } else // Getting result from memory |
| 832 | rc = (Fpos < Qrp->Nblin) ? RC_OK : RC_EF; |
| 833 | |
| 834 | if (rc == RC_OK) { |
| 835 | if (Memory == 2) |
| 836 | Qrp->Nblin++; |
| 837 | |
| 838 | Fpos++; // Used for memory and pos |
| 839 | } // endif rc |
| 840 | |
| 841 | } // endif placed |
| 842 | |
| 843 | if (trace(2)) |
| 844 | htrc(" Read: Rbuf=%d rc=%d\n" , Rbuf, rc); |
| 845 | |
| 846 | return rc; |
| 847 | } // end of ReadDB |
| 848 | |
| 849 | /***********************************************************************/ |
| 850 | /* Data Base Insert write routine for JDBC access method. */ |
| 851 | /***********************************************************************/ |
| 852 | int TDBJDBC::WriteDB(PGLOBAL g) |
| 853 | { |
| 854 | int rc; |
| 855 | |
| 856 | if (Prepared) { |
| 857 | if (SetParameters(g)) { |
| 858 | Werr = true; |
| 859 | rc = RC_FX; |
| 860 | } else if ((rc = Jcp->ExecuteSQL()) == RC_OK) |
| 861 | AftRows += Jcp->m_Aff; |
| 862 | else |
| 863 | Werr = true; |
| 864 | |
| 865 | return rc; |
| 866 | } // endif Prepared |
| 867 | |
| 868 | // Statement was not prepared, we must construct and execute |
| 869 | // an insert query for each line to insert |
| 870 | uint len = Query->GetLength(); |
| 871 | char buf[64]; |
| 872 | |
| 873 | // Make the Insert command value list |
| 874 | for (PCOL colp = Columns; colp; colp = colp->GetNext()) { |
| 875 | if (!colp->GetValue()->IsNull()) { |
| 876 | char *s = colp->GetValue()->GetCharString(buf); |
| 877 | |
| 878 | if (colp->GetResultType() == TYPE_STRING) |
| 879 | Query->Append_quoted(s); |
| 880 | else if (colp->GetResultType() == TYPE_DATE) { |
| 881 | DTVAL *dtv = (DTVAL*)colp->GetValue(); |
| 882 | |
| 883 | if (dtv->IsFormatted()) |
| 884 | Query->Append_quoted(s); |
| 885 | else |
| 886 | Query->Append(s); |
| 887 | |
| 888 | } else |
| 889 | Query->Append(s); |
| 890 | |
| 891 | } else |
| 892 | Query->Append("NULL" ); |
| 893 | |
| 894 | Query->Append(','); |
| 895 | } // endfor colp |
| 896 | |
| 897 | if (unlikely(Query->IsTruncated())) { |
| 898 | strcpy(g->Message, "WriteDB: Out of memory" ); |
| 899 | return RC_FX; |
| 900 | } // endif Query |
| 901 | |
| 902 | Query->RepLast(')'); |
| 903 | |
| 904 | if (trace(2)) |
| 905 | htrc("Inserting: %s\n" , Query->GetStr()); |
| 906 | |
| 907 | rc = Jcp->ExecuteUpdate(Query->GetStr()); |
| 908 | Query->Truncate(len); // Restore query |
| 909 | |
| 910 | if (rc == RC_OK) |
| 911 | AftRows += Jcp->m_Aff; |
| 912 | else |
| 913 | Werr = true; |
| 914 | |
| 915 | return rc; |
| 916 | } // end of WriteDB |
| 917 | |
| 918 | /***********************************************************************/ |
| 919 | /* Data Base delete line routine for JDBC access method. */ |
| 920 | /***********************************************************************/ |
| 921 | int TDBJDBC::DeleteDB(PGLOBAL g, int irc) |
| 922 | { |
| 923 | if (irc == RC_FX) { |
| 924 | if (!Query && MakeCommand(g)) |
| 925 | return RC_FX; |
| 926 | |
| 927 | // Send the DELETE (all) command to the remote table |
| 928 | if (Jcp->ExecuteUpdate(Query->GetStr()) == RC_OK) { |
| 929 | AftRows = Jcp->m_Aff; |
| 930 | sprintf(g->Message, "%s: %d affected rows" , TableName, AftRows); |
| 931 | |
| 932 | if (trace(1)) |
| 933 | htrc("%s\n" , g->Message); |
| 934 | |
| 935 | PushWarning(g, this, 0); // 0 means a Note |
| 936 | return RC_OK; // This is a delete all |
| 937 | } else |
| 938 | return RC_FX; // Error |
| 939 | |
| 940 | } else |
| 941 | return RC_OK; // Ignore |
| 942 | |
| 943 | } // end of DeleteDB |
| 944 | |
| 945 | /***********************************************************************/ |
| 946 | /* Data Base close routine for JDBC access method. */ |
| 947 | /***********************************************************************/ |
| 948 | void TDBJDBC::CloseDB(PGLOBAL g) |
| 949 | { |
| 950 | if (Jcp) |
| 951 | Jcp->Close(); |
| 952 | |
| 953 | if (trace(1)) |
| 954 | htrc("JDBC CloseDB: closing %s\n" , Name); |
| 955 | |
| 956 | if (!Werr && |
| 957 | (Mode == MODE_INSERT || Mode == MODE_UPDATE || Mode == MODE_DELETE)) { |
| 958 | sprintf(g->Message, "%s: %d affected rows" , TableName, AftRows); |
| 959 | |
| 960 | if (trace(1)) |
| 961 | htrc("%s\n" , g->Message); |
| 962 | |
| 963 | PushWarning(g, this, 0); // 0 means a Note |
| 964 | } // endif Mode |
| 965 | |
| 966 | Prepared = false; |
| 967 | } // end of CloseDB |
| 968 | |
| 969 | /* --------------------------- JDBCCOL ------------------------------- */ |
| 970 | |
| 971 | /***********************************************************************/ |
| 972 | /* JDBCCOL public constructor. */ |
| 973 | /***********************************************************************/ |
| 974 | JDBCCOL::JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) |
| 975 | : EXTCOL(cdp, tdbp, cprec, i, am) |
| 976 | { |
| 977 | uuid = false; |
| 978 | } // end of JDBCCOL constructor |
| 979 | |
| 980 | /***********************************************************************/ |
| 981 | /* JDBCCOL private constructor. */ |
| 982 | /***********************************************************************/ |
| 983 | JDBCCOL::JDBCCOL(void) : EXTCOL() |
| 984 | { |
| 985 | uuid = false; |
| 986 | } // end of JDBCCOL constructor |
| 987 | |
| 988 | /***********************************************************************/ |
| 989 | /* JDBCCOL constructor used for copying columns. */ |
| 990 | /* tdbp is the pointer to the new table descriptor. */ |
| 991 | /***********************************************************************/ |
| 992 | JDBCCOL::JDBCCOL(JDBCCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp) |
| 993 | { |
| 994 | uuid = col1->uuid; |
| 995 | } // end of JDBCCOL copy constructor |
| 996 | |
| 997 | /***********************************************************************/ |
| 998 | /* ReadColumn: retrieve the column value via the JDBC driver. */ |
| 999 | /***********************************************************************/ |
| 1000 | void JDBCCOL::ReadColumn(PGLOBAL g) |
| 1001 | { |
| 1002 | PTDBJDBC tdbp = (PTDBJDBC)To_Tdb; |
| 1003 | int i = tdbp->Fpos - 1, n = tdbp->CurNum; |
| 1004 | |
| 1005 | if (tdbp->Memory == 3) { |
| 1006 | // Get the value from the stored memory |
| 1007 | if (Crp->Nulls && Crp->Nulls[i] == '*') { |
| 1008 | Value->Reset(); |
| 1009 | Value->SetNull(true); |
| 1010 | } else { |
| 1011 | Value->SetValue_pvblk(Crp->Kdata, i); |
| 1012 | Value->SetNull(false); |
| 1013 | } // endif Nulls |
| 1014 | |
| 1015 | return; |
| 1016 | } // endif Memory |
| 1017 | |
| 1018 | /*********************************************************************/ |
| 1019 | /* Get the column value. */ |
| 1020 | /*********************************************************************/ |
| 1021 | tdbp->Jcp->SetColumnValue(Rank, Name, Value); |
| 1022 | |
| 1023 | if (tdbp->Memory != 2) |
| 1024 | return; |
| 1025 | |
| 1026 | /*********************************************************************/ |
| 1027 | /* Fill the allocated result structure. */ |
| 1028 | /*********************************************************************/ |
| 1029 | if (Value->IsNull()) { |
| 1030 | if (Crp->Nulls) |
| 1031 | Crp->Nulls[i] = '*'; // Null value |
| 1032 | |
| 1033 | Crp->Kdata->Reset(i); |
| 1034 | } else |
| 1035 | Crp->Kdata->SetValue(Value, i); |
| 1036 | |
| 1037 | } // end of ReadColumn |
| 1038 | |
| 1039 | /***********************************************************************/ |
| 1040 | /* WriteColumn: Convert if necessary. */ |
| 1041 | /***********************************************************************/ |
| 1042 | void JDBCCOL::WriteColumn(PGLOBAL g) |
| 1043 | { |
| 1044 | /*********************************************************************/ |
| 1045 | /* Do convert the column value if necessary. */ |
| 1046 | /*********************************************************************/ |
| 1047 | if (Value != To_Val) |
| 1048 | Value->SetValue_pval(To_Val, FALSE); // Convert the inserted value |
| 1049 | |
| 1050 | } // end of WriteColumn |
| 1051 | |
| 1052 | /* -------------------------- Class TDBXJDC -------------------------- */ |
| 1053 | |
| 1054 | /***********************************************************************/ |
| 1055 | /* Implementation of the TDBXJDC class. */ |
| 1056 | /***********************************************************************/ |
| 1057 | TDBXJDC::TDBXJDC(PJDBCDEF tdp) : TDBJDBC(tdp) |
| 1058 | { |
| 1059 | Cmdlist = NULL; |
| 1060 | Cmdcol = NULL; |
| 1061 | Mxr = tdp->Maxerr; |
| 1062 | Nerr = 0; |
| 1063 | } // end of TDBXJDC constructor |
| 1064 | |
| 1065 | /***********************************************************************/ |
| 1066 | /* Allocate XSRC column description block. */ |
| 1067 | /***********************************************************************/ |
| 1068 | PCOL TDBXJDC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) |
| 1069 | { |
| 1070 | PJSRCCOL colp = new(g)JSRCCOL(cdp, this, cprec, n); |
| 1071 | |
| 1072 | if (!colp->Flag) |
| 1073 | Cmdcol = colp->GetName(); |
| 1074 | |
| 1075 | return colp; |
| 1076 | } // end of MakeCol |
| 1077 | |
| 1078 | /***********************************************************************/ |
| 1079 | /* MakeCMD: make the SQL statement to send to JDBC connection. */ |
| 1080 | /***********************************************************************/ |
| 1081 | PCMD TDBXJDC::MakeCMD(PGLOBAL g) |
| 1082 | { |
| 1083 | PCMD xcmd = NULL; |
| 1084 | |
| 1085 | if (To_CondFil) { |
| 1086 | if (Cmdcol) { |
| 1087 | if (!stricmp(Cmdcol, To_CondFil->Body) && |
| 1088 | (To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) { |
| 1089 | xcmd = To_CondFil->Cmds; |
| 1090 | } else |
| 1091 | strcpy(g->Message, "Invalid command specification filter" ); |
| 1092 | |
| 1093 | } else |
| 1094 | strcpy(g->Message, "No command column in select list" ); |
| 1095 | |
| 1096 | } else if (!Srcdef) |
| 1097 | strcpy(g->Message, "No Srcdef default command" ); |
| 1098 | else |
| 1099 | xcmd = new(g) CMD(g, Srcdef); |
| 1100 | |
| 1101 | return xcmd; |
| 1102 | } // end of MakeCMD |
| 1103 | |
| 1104 | /***********************************************************************/ |
| 1105 | /* XDBC GetMaxSize: returns table size (not always one row). */ |
| 1106 | /***********************************************************************/ |
| 1107 | int TDBXJDC::GetMaxSize(PGLOBAL g) |
| 1108 | { |
| 1109 | if (MaxSize < 0) |
| 1110 | MaxSize = 2; // Just a guess |
| 1111 | |
| 1112 | return MaxSize; |
| 1113 | } // end of GetMaxSize |
| 1114 | |
| 1115 | /***********************************************************************/ |
| 1116 | /* JDBC Access Method opening routine. */ |
| 1117 | /* New method now that this routine is called recursively (last table */ |
| 1118 | /* first in reverse order): index blocks are immediately linked to */ |
| 1119 | /* join block of next table if it exists or else are discarted. */ |
| 1120 | /***********************************************************************/ |
| 1121 | bool TDBXJDC::OpenDB(PGLOBAL g) |
| 1122 | { |
| 1123 | bool rc = false; |
| 1124 | |
| 1125 | if (trace(1)) |
| 1126 | htrc("JDBC OpenDB: tdbp=%p tdb=R%d use=%d mode=%d\n" , |
| 1127 | this, Tdb_No, Use, Mode); |
| 1128 | |
| 1129 | if (Use == USE_OPEN) { |
| 1130 | strcpy(g->Message, "Multiple execution is not allowed" ); |
| 1131 | return true; |
| 1132 | } // endif use |
| 1133 | |
| 1134 | /*********************************************************************/ |
| 1135 | /* Open an JDBC connection for this table. */ |
| 1136 | /* Note: this may not be the proper way to do. Perhaps it is better */ |
| 1137 | /* to test whether a connection is already open for this datasource */ |
| 1138 | /* and if so to allocate just a new result set. But this only for */ |
| 1139 | /* drivers allowing concurency in getting results ??? */ |
| 1140 | /*********************************************************************/ |
| 1141 | if (!Jcp) { |
| 1142 | Jcp = new(g) JDBConn(g, Wrapname); |
| 1143 | } else if (Jcp->IsOpen()) |
| 1144 | Jcp->Close(); |
| 1145 | |
| 1146 | if (Jcp->Connect(&Ops)) |
| 1147 | return true; |
| 1148 | |
| 1149 | Use = USE_OPEN; // Do it now in case we are recursively called |
| 1150 | |
| 1151 | if (Mode != MODE_READ && Mode != MODE_READX) { |
| 1152 | strcpy(g->Message, "No INSERT/DELETE/UPDATE of XJDBC tables" ); |
| 1153 | return true; |
| 1154 | } // endif Mode |
| 1155 | |
| 1156 | /*********************************************************************/ |
| 1157 | /* Get the command to execute. */ |
| 1158 | /*********************************************************************/ |
| 1159 | if (!(Cmdlist = MakeCMD(g))) { |
| 1160 | Jcp->Close(); |
| 1161 | return true; |
| 1162 | } // endif Query |
| 1163 | |
| 1164 | Rows = 1; |
| 1165 | return false; |
| 1166 | } // end of OpenDB |
| 1167 | |
| 1168 | /***********************************************************************/ |
| 1169 | /* ReadDB: Data Base read routine for xdbc access method. */ |
| 1170 | /***********************************************************************/ |
| 1171 | int TDBXJDC::ReadDB(PGLOBAL g) |
| 1172 | { |
| 1173 | if (Cmdlist) { |
| 1174 | int rc; |
| 1175 | |
| 1176 | if (!Query) |
| 1177 | Query = new(g) STRING(g, 0, Cmdlist->Cmd); |
| 1178 | else |
| 1179 | Query->Set(Cmdlist->Cmd); |
| 1180 | |
| 1181 | if ((rc = Jcp->ExecuteCommand(Query->GetStr())) == RC_FX) |
| 1182 | Nerr++; |
| 1183 | |
| 1184 | if (rc == RC_NF) |
| 1185 | AftRows = Jcp->m_Aff; |
| 1186 | else if (rc == RC_OK) |
| 1187 | AftRows = Jcp->m_Ncol; |
| 1188 | |
| 1189 | Fpos++; // Used for progress info |
| 1190 | Cmdlist = (Nerr > Mxr) ? NULL : Cmdlist->Next; |
| 1191 | return RC_OK; |
| 1192 | } else |
| 1193 | return RC_EF; |
| 1194 | |
| 1195 | } // end of ReadDB |
| 1196 | |
| 1197 | /***********************************************************************/ |
| 1198 | /* Data Base write line routine for JDBC access method. */ |
| 1199 | /***********************************************************************/ |
| 1200 | int TDBXJDC::WriteDB(PGLOBAL g) |
| 1201 | { |
| 1202 | strcpy(g->Message, "Execsrc tables are read only" ); |
| 1203 | return RC_FX; |
| 1204 | } // end of DeleteDB |
| 1205 | |
| 1206 | /***********************************************************************/ |
| 1207 | /* Data Base delete line routine for JDBC access method. */ |
| 1208 | /***********************************************************************/ |
| 1209 | int TDBXJDC::DeleteDB(PGLOBAL g, int irc) |
| 1210 | { |
| 1211 | strcpy(g->Message, "NO_XJDBC_DELETE" ); |
| 1212 | return RC_FX; |
| 1213 | } // end of DeleteDB |
| 1214 | |
| 1215 | /* --------------------------- JSRCCOL ------------------------------- */ |
| 1216 | |
| 1217 | /***********************************************************************/ |
| 1218 | /* JSRCCOL public constructor. */ |
| 1219 | /***********************************************************************/ |
| 1220 | JSRCCOL::JSRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am) |
| 1221 | : JDBCCOL(cdp, tdbp, cprec, i, am) |
| 1222 | { |
| 1223 | // Set additional JDBC access method information for column. |
| 1224 | Flag = cdp->GetOffset(); |
| 1225 | } // end of JSRCCOL constructor |
| 1226 | |
| 1227 | /***********************************************************************/ |
| 1228 | /* ReadColumn: set column value according to Flag. */ |
| 1229 | /***********************************************************************/ |
| 1230 | void JSRCCOL::ReadColumn(PGLOBAL g) |
| 1231 | { |
| 1232 | PTDBXJDC tdbp = (PTDBXJDC)To_Tdb; |
| 1233 | |
| 1234 | switch (Flag) { |
| 1235 | case 0: Value->SetValue_psz(tdbp->Query->GetStr()); break; |
| 1236 | case 1: Value->SetValue(tdbp->AftRows); break; |
| 1237 | case 2: Value->SetValue_psz(g->Message); break; |
| 1238 | default: Value->SetValue_psz("Invalid Flag" ); break; |
| 1239 | } // endswitch Flag |
| 1240 | |
| 1241 | } // end of ReadColumn |
| 1242 | |
| 1243 | /***********************************************************************/ |
| 1244 | /* WriteColumn: Should never be called. */ |
| 1245 | /***********************************************************************/ |
| 1246 | void JSRCCOL::WriteColumn(PGLOBAL g) |
| 1247 | { |
| 1248 | // Should never be called |
| 1249 | } // end of WriteColumn |
| 1250 | |
| 1251 | /* ---------------------------TDBJDRV class -------------------------- */ |
| 1252 | |
| 1253 | /***********************************************************************/ |
| 1254 | /* GetResult: Get the list of JDBC drivers. */ |
| 1255 | /***********************************************************************/ |
| 1256 | PQRYRES TDBJDRV::GetResult(PGLOBAL g) |
| 1257 | { |
| 1258 | return JDBCDrivers(g, Maxres, false); |
| 1259 | } // end of GetResult |
| 1260 | |
| 1261 | /* ---------------------------TDBJTB class --------------------------- */ |
| 1262 | |
| 1263 | /***********************************************************************/ |
| 1264 | /* TDBJTB class constructor. */ |
| 1265 | /***********************************************************************/ |
| 1266 | TDBJTB::TDBJTB(PJDBCDEF tdp) : TDBJDRV(tdp) |
| 1267 | { |
| 1268 | Schema = tdp->Tabschema; |
| 1269 | Tab = tdp->Tabname; |
| 1270 | Tabtype = tdp->Tabtyp; |
| 1271 | Ops.Driver = tdp->Driver; |
| 1272 | Ops.Url = tdp->Url; |
| 1273 | Ops.User = tdp->Username; |
| 1274 | Ops.Pwd = tdp->Password; |
| 1275 | Ops.Fsize = 0; |
| 1276 | Ops.Scrollable = false; |
| 1277 | } // end of TDBJTB constructor |
| 1278 | |
| 1279 | /***********************************************************************/ |
| 1280 | /* GetResult: Get the list of JDBC tables. */ |
| 1281 | /***********************************************************************/ |
| 1282 | PQRYRES TDBJTB::GetResult(PGLOBAL g) |
| 1283 | { |
| 1284 | return JDBCTables(g, Schema, Tab, Tabtype, Maxres, false, &Ops); |
| 1285 | } // end of GetResult |
| 1286 | |
| 1287 | /* --------------------------TDBJDBCL class -------------------------- */ |
| 1288 | |
| 1289 | /***********************************************************************/ |
| 1290 | /* TDBJDBCL class constructor. */ |
| 1291 | /***********************************************************************/ |
| 1292 | TDBJDBCL::TDBJDBCL(PJDBCDEF tdp) : TDBJTB(tdp) |
| 1293 | { |
| 1294 | Colpat = tdp->Colpat; |
| 1295 | } // end of TDBJDBCL constructor |
| 1296 | |
| 1297 | /***********************************************************************/ |
| 1298 | /* GetResult: Get the list of JDBC table columns. */ |
| 1299 | /***********************************************************************/ |
| 1300 | PQRYRES TDBJDBCL::GetResult(PGLOBAL g) |
| 1301 | { |
| 1302 | return JDBCColumns(g, Schema, Tab, Colpat, Maxres, false, &Ops); |
| 1303 | } // end of GetResult |
| 1304 | |