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 					if (Mode != MODE_READX) {
589 						Jcp->Close();
590 						return true;
591 					} else
592 						Rbuf = 0;
593 
594 			} else
595 				Rbuf = Qrp->Nblin;
596 
597 			CurNum = 0;
598 			Fpos = 0;
599 			Curpos = 1;
600 		} else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
601 			// new update coming from a trigger or procedure
602 			Query = NULL;
603 			SetCondFil(NULL);
604 			Qrystr = To_Def->GetStringCatInfo(g, "Query_String", "?");
605 		} else {  //if (Mode == MODE_INSERT)
606 		} // endif Mode
607 
608 		return false;
609 	} // endif use
610 
611 	/*********************************************************************/
612 	/*  Open an JDBC connection for this table.                          */
613 	/*  Note: this may not be the proper way to do. Perhaps it is better */
614 	/*  to test whether a connection is already open for this datasource */
615 	/*  and if so to allocate just a new result set. But this only for   */
616 	/*  drivers allowing concurency in getting results ???               */
617 	/*********************************************************************/
618 	if (!Jcp)
619 		Jcp = new(g)JDBConn(g, Wrapname);
620 	else if (Jcp->IsOpen())
621 		Jcp->Close();
622 
623 	if (Jcp->Connect(&Ops))
624 		return true;
625 	else if (Quoted)
626 		Quote = Jcp->GetQuoteChar();
627 
628 	if (Mode != MODE_READ && Mode != MODE_READX)
629 		if (Jcp->SetUUID(g, this))
630 			PushWarning(g, this, 1);
631 
632 	Use = USE_OPEN;       // Do it now in case we are recursively called
633 
634 	/*********************************************************************/
635 	/* Make the command and allocate whatever is used for getting results*/
636 	/*********************************************************************/
637 	if (Mode == MODE_READ || Mode == MODE_READX) {
638 		if (Memory > 1 && !Srcdef) {
639 			int n;
640 
641 			if (!MakeSQL(g, true)) {
642 				// Allocate a Count(*) column
643 				Cnp = new(g)JDBCCOL;
644 				Cnp->InitValue(g);
645 
646 				if ((n = Jcp->GetResultSize(Query->GetStr(), Cnp)) < 0) {
647 					char* msg = PlugDup(g, g->Message);
648 
649 					sprintf(g->Message, "Get result size: %s (rc=%d)", msg, n);
650 					return true;
651 				} else if (n) {
652 					Jcp->m_Rows = n;
653 
654 					if ((Qrp = Jcp->AllocateResult(g, this)))
655 						Memory = 2;            // Must be filled
656 					else {
657 						strcpy(g->Message, "Result set memory allocation failed");
658 						return true;
659 					} // endif n
660 
661 				} else				 // Void result
662 					Memory = 0;
663 
664 				Jcp->m_Rows = 0;
665 			} else
666 				return true;
667 
668 		} // endif Memory
669 
670 		if (!(rc = MakeSQL(g, false))) {
671 //		for (PJDBCCOL colp = (PJDBCCOL)Columns; colp; colp = (PJDBCCOL)colp->GetNext())
672 //			if (!colp->IsSpecial())
673 //				colp->AllocateBuffers(g, Rows);
674 
675 			rc = (Mode == MODE_READ)
676 				? (Jcp->ExecuteQuery(Query->GetStr()) != RC_OK)
677 				: false;
678 		} // endif rc
679 
680 	} else if (Mode == MODE_INSERT) {
681 #if 0
682 		if (!(rc = MakeInsert(g))) {
683 			if (Nparm != Jcp->PrepareSQL(Query->GetStr())) {
684 				strcpy(g->Message, MSG(PARM_CNT_MISS));
685 				rc = true;
686 			} else
687 				rc = BindParameters(g);
688 
689 		} // endif rc
690 #endif // 0
691 		rc = MakeInsert(g);
692 	} else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
693 		rc = false;  // wait for CheckCond before calling MakeCommand(g);
694 	} else
695 		sprintf(g->Message, "Invalid mode %d", Mode);
696 
697 	if (rc) {
698 		Jcp->Close();
699 		return true;
700 	} // endif rc
701 
702 	/*********************************************************************/
703 	/*  Reset statistics values.                                         */
704 	/*********************************************************************/
705 	num_read = num_there = num_eq[0] = num_eq[1] = 0;
706 	return false;
707 } // end of OpenDB
708 
709 #if 0
710 /***********************************************************************/
711 /*  GetRecpos: return the position of last read record.                */
712 /***********************************************************************/
713 int TDBJDBC::GetRecpos(void)
714 {
715 	return Fpos;
716 } // end of GetRecpos
717 #endif // 0
718 
719 /***********************************************************************/
720 /*  SetRecpos: set the position of next read record.                   */
721 /***********************************************************************/
SetRecpos(PGLOBAL g,int recpos)722 bool TDBJDBC::SetRecpos(PGLOBAL g, int recpos)
723 {
724 	if (Jcp->m_Full) {
725 		Fpos = 0;
726 		CurNum = 1;
727 	} else if (Memory == 3) {
728 		Fpos = 0;
729 		CurNum = recpos;
730 	} else if (Ops.Scrollable) {
731 		// Is new position in the current row set?
732 		if (recpos > 0 && recpos <= Rbuf) {
733 		  CurNum = recpos;
734 			Fpos = recpos;
735 		} else {
736 			strcpy(g->Message, "Scrolling out of row set NIY");
737 			return true;
738 		} // endif recpos
739 
740 	} else {
741 		strcpy(g->Message, "This action requires a scrollable cursor");
742 		return true;
743 	} // endif's
744 
745 	// Indicate the table position was externally set
746 	Placed = true;
747 	return false;
748 } // end of SetRecpos
749 
750 /***********************************************************************/
751 /*  Data Base indexed read routine for JDBC access method.             */
752 /***********************************************************************/
ReadKey(PGLOBAL g,OPVAL op,const key_range * kr)753 bool TDBJDBC::ReadKey(PGLOBAL g, OPVAL op, const key_range *kr)
754 {
755 	char c = Quote ? *Quote : 0;
756 	int  rc, oldlen = Query->GetLength();
757 	PHC  hc = To_Def->GetHandler();
758 
759 	if (!(kr || hc->end_range) || op == OP_NEXT ||
760 		     Mode == MODE_UPDATE || Mode == MODE_DELETE) {
761 		if (!kr && Mode == MODE_READX) {
762 			// This is a false indexed read
763 			rc = Jcp->ExecuteQuery((char*)Query->GetStr());
764 			Mode = MODE_READ;
765 			Rows = 1;												 // ???
766 			return (rc != RC_OK);
767 		} // endif key
768 
769 		return false;
770 	} else {
771 		if (hc->MakeKeyWhere(g, Query, op, c, kr))
772 			return true;
773 
774 		if (To_CondFil) {
775 			if (To_CondFil->Idx != hc->active_index) {
776 				To_CondFil->Idx = hc->active_index;
777 				To_CondFil->Body= (char*)PlugSubAlloc(g, NULL, 0);
778 				*To_CondFil->Body= 0;
779 
780 				if ((To_CondFil = hc->CheckCond(g, To_CondFil, Cond)))
781 					PlugSubAlloc(g, NULL, strlen(To_CondFil->Body) + 1);
782 
783 			} // endif active_index
784 
785 			if (To_CondFil)
786 				if (Query->Append(" AND ") || Query->Append(To_CondFil->Body)) {
787 					strcpy(g->Message, "Readkey: Out of memory");
788 					return true;
789 				} // endif Append
790 
791 		} // endif To_Condfil
792 
793 		Mode = MODE_READ;
794 	} // endif's op
795 
796 	if (trace(33))
797 		htrc("JDBC ReadKey: Query=%s\n", Query->GetStr());
798 
799 	rc = Jcp->ExecuteQuery((char*)Query->GetStr());
800 	Query->Truncate(oldlen);
801 	Rows = 1;                        // ???
802 	return (rc != RC_OK);
803 } // end of ReadKey
804 
805 /***********************************************************************/
806 /*  Data Base read routine for JDBC access method.                     */
807 /***********************************************************************/
ReadDB(PGLOBAL g)808 int TDBJDBC::ReadDB(PGLOBAL g)
809 {
810 	int  rc;
811 
812 	if (trace(2))
813 		htrc("JDBC ReadDB: R%d Mode=%d\n", GetTdb_No(), Mode);
814 
815 	if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
816 		if (!Query && MakeCommand(g))
817 			return RC_FX;
818 
819 		// Send the UPDATE/DELETE command to the remote table
820 		rc = Jcp->ExecuteUpdate(Query->GetStr());
821 
822 		if (rc == RC_OK) {
823 			AftRows = Jcp->m_Aff;
824 			return RC_EF;               // Nothing else to do
825 		} else {
826 			Werr = true;
827 			return RC_FX;
828 		} // endif rc
829 
830 	} // endif Mode
831 
832 	/*********************************************************************/
833 	/*  Now start the reading process.                                   */
834 	/*  Here is the place to fetch the line(s).                          */
835 	/*********************************************************************/
836 	if (Placed) {
837 		if (Fpos && CurNum >= 0)
838 			Rbuf = Jcp->Fetch((Curpos = Fpos));
839 		else
840 			Fpos = CurNum;
841 
842 		rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
843 		Placed = false;
844 	} else {
845 		if (Memory != 3) {
846 			if (++CurNum >= Rbuf) {
847 				Rbuf = Jcp->Fetch();
848 				Curpos = Fpos + 1;
849 				CurNum = 0;
850 			} // endif CurNum
851 
852 			rc = (Rbuf > 0) ? RC_OK : (Rbuf == 0) ? RC_EF : RC_FX;
853 		} else                 // Getting result from memory
854 			rc = (Fpos < Qrp->Nblin) ? RC_OK : RC_EF;
855 
856 		if (rc == RC_OK) {
857 			if (Memory == 2)
858 				Qrp->Nblin++;
859 
860 			Fpos++;                // Used for memory and pos
861 		} // endif rc
862 
863 	} // endif placed
864 
865 	if (trace(2))
866 		htrc(" Read: Rbuf=%d rc=%d\n", Rbuf, rc);
867 
868 	return rc;
869 } // end of ReadDB
870 
871 /***********************************************************************/
872 /*  Data Base Insert write routine for JDBC access method.             */
873 /***********************************************************************/
WriteDB(PGLOBAL g)874 int TDBJDBC::WriteDB(PGLOBAL g)
875 {
876 	int  rc;
877 
878 	if (Prepared) {
879 		if (SetParameters(g)) {
880 			Werr = true;
881 			rc = RC_FX;
882 		} else if ((rc = Jcp->ExecuteSQL()) == RC_OK)
883 			AftRows += Jcp->m_Aff;
884 		else
885 			Werr = true;
886 
887 		return rc;
888 	} // endif  Prepared
889 
890 	// Statement was not prepared, we must construct and execute
891 	// an insert query for each line to insert
892 	uint len = Query->GetLength();
893 	char buf[64];
894 
895 	// Make the Insert command value list
896 	for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
897 		if (!colp->GetValue()->IsNull()) {
898 			char *s = colp->GetValue()->GetCharString(buf);
899 
900 			if (colp->GetResultType() == TYPE_STRING)
901 				Query->Append_quoted(s);
902 			else if (colp->GetResultType() == TYPE_DATE) {
903 				DTVAL *dtv = (DTVAL*)colp->GetValue();
904 
905 				if (dtv->IsFormatted())
906 					Query->Append_quoted(s);
907 				else
908 					Query->Append(s);
909 
910 			} else
911 				Query->Append(s);
912 
913 		} else
914 			Query->Append("NULL");
915 
916 		Query->Append(',');
917 	} // endfor colp
918 
919 	if (unlikely(Query->IsTruncated())) {
920 		strcpy(g->Message, "WriteDB: Out of memory");
921 		return RC_FX;
922 	} // endif Query
923 
924 	Query->RepLast(')');
925 
926 	if (trace(2))
927 		htrc("Inserting: %s\n", Query->GetStr());
928 
929 	rc = Jcp->ExecuteUpdate(Query->GetStr());
930 	Query->Truncate(len);     // Restore query
931 
932 	if (rc == RC_OK)
933 		AftRows += Jcp->m_Aff;
934 	else
935 		Werr = true;
936 
937 	return rc;
938 } // end of WriteDB
939 
940 /***********************************************************************/
941 /*  Data Base delete line routine for JDBC access method.              */
942 /***********************************************************************/
DeleteDB(PGLOBAL g,int irc)943 int TDBJDBC::DeleteDB(PGLOBAL g, int irc)
944 {
945 	if (irc == RC_FX) {
946 		if (!Query && MakeCommand(g))
947 			return RC_FX;
948 
949 		// Send the DELETE (all) command to the remote table
950 		if (Jcp->ExecuteUpdate(Query->GetStr()) == RC_OK) {
951 			AftRows = Jcp->m_Aff;
952 			sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
953 
954 			if (trace(1))
955 				htrc("%s\n", g->Message);
956 
957 			PushWarning(g, this, 0);    // 0 means a Note
958 			return RC_OK;               // This is a delete all
959 		} else
960 			return RC_FX;               // Error
961 
962 	} else
963 		return RC_OK;                 // Ignore
964 
965 } // end of DeleteDB
966 
967 /***********************************************************************/
968 /*  Data Base close routine for JDBC access method.                    */
969 /***********************************************************************/
CloseDB(PGLOBAL g)970 void TDBJDBC::CloseDB(PGLOBAL g)
971 {
972 	if (Jcp)
973 		Jcp->Close();
974 
975 	if (trace(1))
976 		htrc("JDBC CloseDB: closing %s\n", Name);
977 
978 	if (!Werr &&
979 		(Mode == MODE_INSERT || Mode == MODE_UPDATE || Mode == MODE_DELETE)) {
980 		sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
981 
982 		if (trace(1))
983 			htrc("%s\n", g->Message);
984 
985 		PushWarning(g, this, 0);    // 0 means a Note
986 	}	// endif Mode
987 
988 	Prepared = false;
989 } // end of CloseDB
990 
991 /* --------------------------- JDBCCOL ------------------------------- */
992 
993 /***********************************************************************/
994 /*  JDBCCOL public constructor.                                        */
995 /***********************************************************************/
JDBCCOL(PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i,PCSZ am)996 JDBCCOL::JDBCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
997 	     : EXTCOL(cdp, tdbp, cprec, i, am)
998 {
999 	uuid = false;
1000 } // end of JDBCCOL constructor
1001 
1002 /***********************************************************************/
1003 /*  JDBCCOL private constructor.                                       */
1004 /***********************************************************************/
JDBCCOL(void)1005 JDBCCOL::JDBCCOL(void) : EXTCOL()
1006 {
1007 	uuid = false;
1008 } // end of JDBCCOL constructor
1009 
1010 /***********************************************************************/
1011 /*  JDBCCOL constructor used for copying columns.                      */
1012 /*  tdbp is the pointer to the new table descriptor.                   */
1013 /***********************************************************************/
JDBCCOL(JDBCCOL * col1,PTDB tdbp)1014 JDBCCOL::JDBCCOL(JDBCCOL *col1, PTDB tdbp) : EXTCOL(col1, tdbp)
1015 {
1016 	uuid = col1->uuid;
1017 } // end of JDBCCOL copy constructor
1018 
1019 /***********************************************************************/
1020 /*  ReadColumn: retrieve the column value via the JDBC driver.         */
1021 /***********************************************************************/
ReadColumn(PGLOBAL g)1022 void JDBCCOL::ReadColumn(PGLOBAL g)
1023 {
1024 	PTDBJDBC tdbp = (PTDBJDBC)To_Tdb;
1025 	int i = tdbp->Fpos - 1, n = tdbp->CurNum;
1026 
1027 	if (tdbp->Memory == 3) {
1028 		// Get the value from the stored memory
1029 		if (Crp->Nulls && Crp->Nulls[i] == '*') {
1030 			Value->Reset();
1031 			Value->SetNull(true);
1032 		} else {
1033 			Value->SetValue_pvblk(Crp->Kdata, i);
1034 			Value->SetNull(false);
1035 		} // endif Nulls
1036 
1037 		return;
1038 	} // endif Memory
1039 
1040 	/*********************************************************************/
1041 	/*  Get the column value.                                            */
1042 	/*********************************************************************/
1043 	tdbp->Jcp->SetColumnValue(Rank, Name, Value);
1044 
1045 	if (tdbp->Memory != 2)
1046 		return;
1047 
1048 	/*********************************************************************/
1049 	/*  Fill the allocated result structure.                             */
1050 	/*********************************************************************/
1051 	if (Value->IsNull()) {
1052 		if (Crp->Nulls)
1053 			Crp->Nulls[i] = '*';           // Null value
1054 
1055 		Crp->Kdata->Reset(i);
1056 	} else
1057 		Crp->Kdata->SetValue(Value, i);
1058 
1059 } // end of ReadColumn
1060 
1061 /***********************************************************************/
1062 /*  WriteColumn: Convert if necessary.                                 */
1063 /***********************************************************************/
WriteColumn(PGLOBAL g)1064 void JDBCCOL::WriteColumn(PGLOBAL g)
1065 {
1066 	/*********************************************************************/
1067 	/*  Do convert the column value if necessary.                        */
1068 	/*********************************************************************/
1069 	if (Value != To_Val)
1070 		Value->SetValue_pval(To_Val, FALSE);   // Convert the inserted value
1071 
1072 } // end of WriteColumn
1073 
1074 /* -------------------------- Class TDBXJDC -------------------------- */
1075 
1076 /***********************************************************************/
1077 /*  Implementation of the TDBXJDC class.                               */
1078 /***********************************************************************/
TDBXJDC(PJDBCDEF tdp)1079 TDBXJDC::TDBXJDC(PJDBCDEF tdp) : TDBJDBC(tdp)
1080 {
1081 	Cmdlist = NULL;
1082 	Cmdcol = NULL;
1083 	Mxr = tdp->Maxerr;
1084 	Nerr = 0;
1085 } // end of TDBXJDC constructor
1086 
1087 /***********************************************************************/
1088 /*  Allocate XSRC column description block.                            */
1089 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)1090 PCOL TDBXJDC::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
1091 {
1092 	PJSRCCOL colp = new(g)JSRCCOL(cdp, this, cprec, n);
1093 
1094 	if (!colp->Flag)
1095 		Cmdcol = colp->GetName();
1096 
1097 	return colp;
1098 } // end of MakeCol
1099 
1100 /***********************************************************************/
1101 /*  MakeCMD: make the SQL statement to send to JDBC connection.        */
1102 /***********************************************************************/
MakeCMD(PGLOBAL g)1103 PCMD TDBXJDC::MakeCMD(PGLOBAL g)
1104 {
1105 	PCMD xcmd = NULL;
1106 
1107 	if (To_CondFil) {
1108 		if (Cmdcol) {
1109 			if (!stricmp(Cmdcol, To_CondFil->Body) &&
1110 				(To_CondFil->Op == OP_EQ || To_CondFil->Op == OP_IN)) {
1111 				xcmd = To_CondFil->Cmds;
1112 			} else
1113 				strcpy(g->Message, "Invalid command specification filter");
1114 
1115 		} else
1116 			strcpy(g->Message, "No command column in select list");
1117 
1118 	} else if (!Srcdef)
1119 		strcpy(g->Message, "No Srcdef default command");
1120 	else
1121 		xcmd = new(g) CMD(g, Srcdef);
1122 
1123 	return xcmd;
1124 } // end of MakeCMD
1125 
1126 /***********************************************************************/
1127 /*  XDBC GetMaxSize: returns table size (not always one row).          */
1128 /***********************************************************************/
GetMaxSize(PGLOBAL g)1129 int TDBXJDC::GetMaxSize(PGLOBAL g)
1130 {
1131 	if (MaxSize < 0)
1132 		MaxSize = 2;             // Just a guess
1133 
1134 	return MaxSize;
1135 } // end of GetMaxSize
1136 
1137 /***********************************************************************/
1138 /*  JDBC Access Method opening routine.                                */
1139 /*  New method now that this routine is called recursively (last table */
1140 /*  first in reverse order): index blocks are immediately linked to    */
1141 /*  join block of next table if it exists or else are discarted.       */
1142 /***********************************************************************/
OpenDB(PGLOBAL g)1143 bool TDBXJDC::OpenDB(PGLOBAL g)
1144 {
1145 	bool rc = false;
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