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