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