1 /************ Jdbconn C++ Functions Source Code File (.CPP) ************/
2 /* Name: JDBCONN.CPP Version 1.2 */
3 /* */
4 /* (C) Copyright to the author Olivier BERTRAND 2016-2018 */
5 /* */
6 /* This file contains the JDBC connection classes functions. */
7 /***********************************************************************/
8
9 #if defined(_WIN32)
10 // This is needed for RegGetValue
11 #define _WINVER 0x0601
12 #undef _WIN32_WINNT
13 #define _WIN32_WINNT 0x0601
14 #endif // _WIN32
15
16 /***********************************************************************/
17 /* Include relevant MariaDB header file. */
18 /***********************************************************************/
19 #include <my_global.h>
20 #include <m_string.h>
21 #if defined(_WIN32)
22 //nclude <io.h>
23 //nclude <fcntl.h>
24 #include <direct.h> // for getcwd
25 #if defined(__BORLANDC__)
26 #define __MFC_COMPAT__ // To define min/max as macro
27 #endif // __BORLANDC__
28 //#include <windows.h>
29 #else // !_WIN32
30 #if defined(UNIX)
31 #include <errno.h>
32 #else // !UNIX
33 //nclude <io.h>
34 #endif // !UNIX
35 #include <stdio.h>
36 #include <stdlib.h> // for getenv
37 //nclude <fcntl.h>
38 #define NODW
39 #endif // !_WIN32
40
41 /***********************************************************************/
42 /* Required objects includes. */
43 /***********************************************************************/
44 #include "global.h"
45 #include "plgdbsem.h"
46 #include "xobject.h"
47 #include "xtable.h"
48 #include "tabext.h"
49 #include "tabjdbc.h"
50 //#include "jdbconn.h"
51 #include "resource.h"
52 #include "valblk.h"
53 #include "osutil.h"
54
55
56 //#if defined(_WIN32)
57 //extern "C" HINSTANCE s_hModule; // Saved module handle
58 //#endif // _WIN32
59 #define nullptr 0
60
61 TYPCONV GetTypeConv();
62 int GetConvSize();
63 //extern char *JvmPath; // The connect_jvm_path global variable value
64 //extern char *ClassPath; // The connect_class_path global variable value
65
66 //char *GetJavaWrapper(void); // The connect_java_wrapper variable value
67
68 /***********************************************************************/
69 /* Some macro's (should be defined elsewhere to be more accessible) */
70 /***********************************************************************/
71 //#if defined(_DEBUG)
72 //#define ASSERT(f) assert(f)
73 //#define DEBUG_ONLY(f) (f)
74 //#else // !_DEBUG
75 //#define ASSERT(f) ((void)0)
76 //#define DEBUG_ONLY(f) ((void)0)
77 //#endif // !_DEBUG
78
79 // To avoid gcc warning
80 int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v);
81
82 /***********************************************************************/
83 /* GetJDBCType: returns the SQL_TYPE corresponding to a PLG type. */
84 /***********************************************************************/
GetJDBCType(int type)85 static short GetJDBCType(int type)
86 {
87 short tp = 0; // NULL
88
89 switch (type) {
90 case TYPE_STRING: tp = 12; break; // VARCHAR
91 case TYPE_SHORT: tp = 5; break; // SMALLINT
92 case TYPE_INT: tp = 4; break; // INTEGER
93 case TYPE_DATE: tp = 93; break; // DATE
94 //case TYPE_TIME: tp = 92; break; // TIME
95 //case TYPE_TIMESTAMP: tp = 93; break; // TIMESTAMP
96 case TYPE_BIGINT: tp = -5; break; // BIGINT
97 case TYPE_DOUBLE: tp = 8; break; // DOUBLE
98 case TYPE_TINY: tp = -6; break; // TINYINT
99 case TYPE_DECIM: tp = 3; break; // DECIMAL
100 } // endswitch type
101
102 return tp;
103 } // end of GetJDBCType
104
105 /***********************************************************************/
106 /* TranslateJDBCType: translate a JDBC Type to a PLG type. */
107 /***********************************************************************/
TranslateJDBCType(int stp,char * tn,int prec,int & len,char & v)108 int TranslateJDBCType(int stp, char *tn, int prec, int& len, char& v)
109 {
110 int type;
111
112 switch (stp) {
113 case -1: // LONGVARCHAR, TEXT
114 case -16: // LONGNVARCHAR, NTEXT (unicode)
115 if (GetTypeConv() != TPC_YES)
116 return TYPE_ERROR;
117 else
118 len = MY_MIN(abs(len), GetConvSize());
119
120 // Pass through
121 case 12: // VARCHAR
122 if (tn && !stricmp(tn, "TEXT"))
123 // Postgresql returns 12 for TEXT
124 if (GetTypeConv() == TPC_NO)
125 return TYPE_ERROR;
126
127 // Postgresql can return this
128 if (len == 0x7FFFFFFF)
129 len = GetConvSize();
130
131 // Pass through
132 case -9: // NVARCHAR (unicode)
133 // Postgresql can return this when size is unknown
134 if (len == 0x7FFFFFFF)
135 len = GetConvSize();
136
137 v = 'V';
138 // Pass through
139 case 1: // CHAR
140 case -15: // NCHAR (unicode)
141 case -8: // ROWID
142 type = TYPE_STRING;
143 break;
144 case 2: // NUMERIC
145 case 3: // DECIMAL
146 case -3: // VARBINARY
147 type = TYPE_DECIM;
148 break;
149 case 4: // INTEGER
150 type = TYPE_INT;
151 break;
152 case 5: // SMALLINT
153 type = TYPE_SHORT;
154 break;
155 case -6: // TINYINT
156 case -7: // BIT
157 case 16: // BOOLEAN
158 type = TYPE_TINY;
159 break;
160 case 6: // FLOAT
161 case 7: // REAL
162 case 8: // DOUBLE
163 type = TYPE_DOUBLE;
164 break;
165 case 93: // TIMESTAMP, DATETIME
166 type = TYPE_DATE;
167 len = 19 + ((prec) ? (prec+1) : 0);
168 v = (tn && toupper(tn[0]) == 'T') ? 'S' : 'E';
169 break;
170 case 91: // DATE, YEAR
171 type = TYPE_DATE;
172
173 if (!tn || toupper(tn[0]) != 'Y') {
174 len = 10;
175 v = 'D';
176 } else {
177 len = 4;
178 v = 'Y';
179 } // endif len
180
181 break;
182 case 92: // TIME
183 type = TYPE_DATE;
184 len = 8 + ((prec) ? (prec + 1) : 0);
185 v = 'T';
186 break;
187 case -5: // BIGINT
188 type = TYPE_BIGINT;
189 break;
190 case 1111: // UNKNOWN or UUID
191 if (!tn || !stricmp(tn, "UUID")) {
192 type = TYPE_STRING;
193 len = 36;
194 break;
195 } // endif tn
196
197 // Pass through
198 case 0: // NULL
199 case -2: // BINARY
200 case -4: // LONGVARBINARY
201 case 70: // DATALINK
202 case 2000: // JAVA_OBJECT
203 case 2001: // DISTINCT
204 case 2002: // STRUCT
205 case 2003: // ARRAY
206 case 2004: // BLOB
207 case 2005: // CLOB
208 case 2006: // REF
209 case 2009: // SQLXML
210 case 2011: // NCLOB
211 default:
212 type = TYPE_ERROR;
213 len = 0;
214 } // endswitch type
215
216 return type;
217 } // end of TranslateJDBCType
218
219 /***********************************************************************/
220 /* A helper class to split an optionally qualified table name into */
221 /* components. */
222 /* These formats are understood: */
223 /* "CatalogName.SchemaName.TableName" */
224 /* "SchemaName.TableName" */
225 /* "TableName" */
226 /***********************************************************************/
227 class SQLQualifiedName {
228 static const uint max_parts = 3; // Catalog.Schema.Table
229 MYSQL_LEX_STRING m_part[max_parts];
230 char m_buf[512];
231
lex_string_set(MYSQL_LEX_STRING * S,char * str,size_t length)232 void lex_string_set(MYSQL_LEX_STRING *S, char *str, size_t length)
233 {
234 S->str = str;
235 S->length = length;
236 } // end of lex_string_set
237
lex_string_shorten_down(MYSQL_LEX_STRING * S,size_t offs)238 void lex_string_shorten_down(MYSQL_LEX_STRING *S, size_t offs)
239 {
240 DBUG_ASSERT(offs <= S->length);
241 S->str += offs;
242 S->length -= offs;
243 } // end of lex_string_shorten_down
244
245 /*********************************************************************/
246 /* Find the rightmost '.' delimiter and return the length */
247 /* of the qualifier, including the rightmost '.' delimier. */
248 /* For example, for the string {"a.b.c",5} it will return 4, */
249 /* which is the length of the qualifier "a.b." */
250 /*********************************************************************/
lex_string_find_qualifier(MYSQL_LEX_STRING * S)251 size_t lex_string_find_qualifier(MYSQL_LEX_STRING *S)
252 {
253 size_t i;
254 for (i = S->length; i > 0; i--)
255 {
256 if (S->str[i - 1] == '.')
257 {
258 S->str[i - 1] = '\0';
259 return i;
260 }
261 }
262 return 0;
263 } // end of lex_string_find_qualifier
264
265 public:
266 /*********************************************************************/
267 /* Initialize to the given optionally qualified name. */
268 /* NULL pointer in "name" is supported. */
269 /* name qualifier has precedence over schema. */
270 /*********************************************************************/
SQLQualifiedName(JCATPARM * cap)271 SQLQualifiedName(JCATPARM *cap)
272 {
273 const char *name = (const char *)cap->Tab;
274 char *db = (char *)cap->DB;
275 size_t len, i;
276
277 // Initialize the parts
278 for (i = 0; i < max_parts; i++)
279 lex_string_set(&m_part[i], NULL, 0);
280
281 if (name) {
282 // Initialize the first (rightmost) part
283 lex_string_set(&m_part[0], m_buf,
284 strmake(m_buf, name, sizeof(m_buf) - 1) - m_buf);
285
286 // Initialize the other parts, if exist.
287 for (i = 1; i < max_parts; i++) {
288 if (!(len = lex_string_find_qualifier(&m_part[i - 1])))
289 break;
290
291 lex_string_set(&m_part[i], m_part[i - 1].str, len - 1);
292 lex_string_shorten_down(&m_part[i - 1], len);
293 } // endfor i
294
295 } // endif name
296
297 // If it was not specified, set schema as the passed db name
298 if (db && !m_part[1].length)
299 lex_string_set(&m_part[1], db, strlen(db));
300
301 } // end of SQLQualifiedName
302
ptr(uint i)303 char *ptr(uint i)
304 {
305 DBUG_ASSERT(i < max_parts);
306 return (char *)(m_part[i].length ? m_part[i].str : NULL);
307 } // end of ptr
308
length(uint i)309 size_t length(uint i)
310 {
311 DBUG_ASSERT(i < max_parts);
312 return m_part[i].length;
313 } // end of length
314
315 }; // end of class SQLQualifiedName
316
317 /***********************************************************************/
318 /* Allocate the structure used to refer to the result set. */
319 /***********************************************************************/
AllocCatInfo(PGLOBAL g,JCATINFO fid,PCSZ db,PCSZ tab,PQRYRES qrp)320 static JCATPARM *AllocCatInfo(PGLOBAL g, JCATINFO fid, PCSZ db,
321 PCSZ tab, PQRYRES qrp)
322 {
323 JCATPARM *cap;
324
325 if ((cap = (JCATPARM *)PlgDBSubAlloc(g, NULL, sizeof(JCATPARM)))) {
326 memset(cap, 0, sizeof(JCATPARM));
327 cap->Id = fid;
328 cap->Qrp = qrp;
329 cap->DB = db;
330 cap->Tab = tab;
331 } // endif cap
332
333 return cap;
334 } // end of AllocCatInfo
335
336 /***********************************************************************/
337 /* JDBCColumns: constructs the result blocks containing all columns */
338 /* of a JDBC table that will be retrieved by GetData commands. */
339 /***********************************************************************/
JDBCColumns(PGLOBAL g,PCSZ db,PCSZ table,PCSZ colpat,int maxres,bool info,PJPARM sjp)340 PQRYRES JDBCColumns(PGLOBAL g, PCSZ db, PCSZ table, PCSZ colpat,
341 int maxres, bool info, PJPARM sjp)
342 {
343 int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
344 TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT,
345 TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
346 XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_TABNAME, FLD_NAME,
347 FLD_TYPE, FLD_TYPENAME, FLD_PREC, FLD_LENGTH,
348 FLD_SCALE, FLD_RADIX, FLD_NULL, FLD_REM};
349 unsigned int length[] = {0, 0, 0, 0, 6, 0, 10, 10, 6, 6, 6, 0};
350 bool b[] = {true, true, false, false, false, false, false, false, true, true, false, true};
351 int i, n, ncol = 12;
352 PCOLRES crp;
353 PQRYRES qrp;
354 JCATPARM *cap;
355 JDBConn *jcp = NULL;
356
357 /************************************************************************/
358 /* Do an evaluation of the result size. */
359 /************************************************************************/
360 if (!info) {
361 jcp = new(g)JDBConn(g, NULL);
362
363 if (jcp->Connect(sjp)) // openReadOnly + noJDBCdialog
364 return NULL;
365
366 if (table && !strchr(table, '%')) {
367 // We fix a MySQL limit because some data sources return 32767
368 n = jcp->GetMaxValue(1); // MAX_COLUMNS_IN_TABLE)
369 maxres = (n > 0) ? MY_MIN(n, 4096) : 4096;
370 } else if (!maxres)
371 maxres = 20000;
372
373 // n = jcp->GetMaxValue(2); MAX_CATALOG_NAME_LEN
374 // length[0] = (n) ? (n + 1) : 0;
375 // n = jcp->GetMaxValue(3); MAX_SCHEMA_NAME_LEN
376 // length[1] = (n) ? (n + 1) : 0;
377 // n = jcp->GetMaxValue(4); MAX_TABLE_NAME_LEN
378 // length[2] = (n) ? (n + 1) : 0;
379 n = jcp->GetMaxValue(5); // MAX_COLUMN_NAME_LEN
380 length[3] = (n > 0) ? (n + 1) : 128;
381 } else { // Info table
382 maxres = 0;
383 length[0] = 128;
384 length[1] = 128;
385 length[2] = 128;
386 length[3] = 128;
387 length[5] = 30;
388 length[11] = 255;
389 } // endif jcp
390
391 if (trace(1))
392 htrc("JDBCColumns: max=%d len=%d,%d,%d,%d\n",
393 maxres, length[0], length[1], length[2], length[3]);
394
395 /************************************************************************/
396 /* Allocate the structures used to refer to the result set. */
397 /************************************************************************/
398 qrp = PlgAllocResult(g, ncol, maxres, IDS_COLUMNS,
399 buftyp, fldtyp, length, false, true);
400
401 for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
402 if (b[i])
403 crp->Kdata->SetNullable(true);
404
405 if (info || !qrp) // Info table
406 return qrp;
407
408 if (trace(1))
409 htrc("Getting col results ncol=%d\n", qrp->Nbcol);
410
411 if (!(cap = AllocCatInfo(g, JCAT_COL, db, table, qrp)))
412 return NULL;
413
414 // Colpat cannot be null or empty for some drivers
415 cap->Pat = (colpat && *colpat) ? colpat : PlugDup(g, "%");
416
417 /************************************************************************/
418 /* Now get the results into blocks. */
419 /************************************************************************/
420 if ((n = jcp->GetCatInfo(cap)) >= 0) {
421 qrp->Nblin = n;
422 // ResetNullValues(cap);
423
424 if (trace(1))
425 htrc("Columns: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
426
427 } else
428 qrp = NULL;
429
430 /* Cleanup */
431 jcp->Close();
432
433 /************************************************************************/
434 /* Return the result pointer for use by GetData routines. */
435 /************************************************************************/
436 return qrp;
437 } // end of JDBCColumns
438
439 /**************************************************************************/
440 /* JDBCSrcCols: constructs the result blocks containing the */
441 /* description of all the columns of a Srcdef option. */
442 /**************************************************************************/
JDBCSrcCols(PGLOBAL g,PCSZ src,PJPARM sjp)443 PQRYRES JDBCSrcCols(PGLOBAL g, PCSZ src, PJPARM sjp)
444 {
445 char *sqry;
446 PQRYRES qrp;
447 JDBConn *jcp = new(g)JDBConn(g, NULL);
448
449 if (jcp->Connect(sjp))
450 return NULL;
451
452 if (strstr(src, "%s")) {
453 // Place holder for an eventual where clause
454 sqry = (char*)PlugSubAlloc(g, NULL, strlen(src) + 2);
455 sprintf(sqry, src, "1=1"); // dummy where clause
456 } else
457 sqry = (char*)src;
458
459 qrp = jcp->GetMetaData(g, sqry);
460 jcp->Close();
461 return qrp;
462 } // end of JDBCSrcCols
463
464 /**************************************************************************/
465 /* JDBCTables: constructs the result blocks containing all tables in */
466 /* an JDBC database that will be retrieved by GetData commands. */
467 /**************************************************************************/
JDBCTables(PGLOBAL g,PCSZ db,PCSZ tabpat,PCSZ tabtyp,int maxres,bool info,PJPARM sjp)468 PQRYRES JDBCTables(PGLOBAL g, PCSZ db, PCSZ tabpat, PCSZ tabtyp,
469 int maxres, bool info, PJPARM sjp)
470 {
471 int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
472 TYPE_STRING, TYPE_STRING};
473 XFLD fldtyp[] = {FLD_CAT, FLD_SCHEM, FLD_NAME, FLD_TYPE, FLD_REM};
474 unsigned int length[] = {0, 0, 0, 16, 0};
475 bool b[] = {true, true, false, false, true};
476 int i, n, ncol = 5;
477 PCOLRES crp;
478 PQRYRES qrp;
479 JCATPARM *cap;
480 JDBConn *jcp = NULL;
481
482 /************************************************************************/
483 /* Do an evaluation of the result size. */
484 /************************************************************************/
485 if (!info) {
486 /**********************************************************************/
487 /* Open the connection with the JDBC data source. */
488 /**********************************************************************/
489 jcp = new(g)JDBConn(g, NULL);
490
491 if (jcp->Connect(sjp))
492 return NULL;
493
494 if (!maxres)
495 maxres = 10000; // This is completely arbitrary
496
497 n = jcp->GetMaxValue(2); // Max catalog name length
498
499 // if (n < 0)
500 // return NULL;
501
502 length[0] = (n > 0) ? (n + 1) : 0;
503 n = jcp->GetMaxValue(3); // Max schema name length
504 length[1] = (n > 0) ? (n + 1) : 0;
505 n = jcp->GetMaxValue(4); // Max table name length
506 length[2] = (n > 0) ? (n + 1) : 128;
507 } else {
508 maxres = 0;
509 length[0] = 128;
510 length[1] = 128;
511 length[2] = 128;
512 length[4] = 255;
513 } // endif info
514
515 if (trace(1))
516 htrc("JDBCTables: max=%d len=%d,%d\n", maxres, length[0], length[1]);
517
518 /************************************************************************/
519 /* Allocate the structures used to refer to the result set. */
520 /************************************************************************/
521 qrp = PlgAllocResult(g, ncol, maxres, IDS_TABLES, buftyp,
522 fldtyp, length, false, true);
523
524 for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next)
525 if (b[i])
526 crp->Kdata->SetNullable(true);
527
528 if (info || !qrp)
529 return qrp;
530
531 // Tabpat cannot be null or empty for some drivers
532 if (!(cap = AllocCatInfo(g, JCAT_TAB, db,
533 (tabpat && *tabpat) ? tabpat : PlugDup(g, "%"), qrp)))
534 return NULL;
535
536 cap->Pat = tabtyp;
537
538 if (trace(1))
539 htrc("Getting table results ncol=%d\n", cap->Qrp->Nbcol);
540
541 /************************************************************************/
542 /* Now get the results into blocks. */
543 /************************************************************************/
544 if ((n = jcp->GetCatInfo(cap)) >= 0) {
545 qrp->Nblin = n;
546 // ResetNullValues(cap);
547
548 if (trace(1))
549 htrc("Tables: NBCOL=%d NBLIN=%d\n", qrp->Nbcol, qrp->Nblin);
550
551 } else
552 qrp = NULL;
553
554 /************************************************************************/
555 /* Close any local connection. */
556 /************************************************************************/
557 jcp->Close();
558
559 /************************************************************************/
560 /* Return the result pointer for use by GetData routines. */
561 /************************************************************************/
562 return qrp;
563 } // end of JDBCTables
564
565 /*************************************************************************/
566 /* JDBCDrivers: constructs the result blocks containing all JDBC */
567 /* drivers available on the local host. */
568 /* Called with info=true to have result column names. */
569 /*************************************************************************/
JDBCDrivers(PGLOBAL g,int maxres,bool info)570 PQRYRES JDBCDrivers(PGLOBAL g, int maxres, bool info)
571 {
572 int buftyp[] ={TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING};
573 XFLD fldtyp[] ={FLD_NAME, FLD_EXTRA, FLD_DEFAULT, FLD_REM };
574 unsigned int length[] ={ 128, 32, 4, 256 };
575 bool b[] ={ false, false, false, true };
576 int i, ncol = 4;
577 PCOLRES crp;
578 PQRYRES qrp;
579 JDBConn *jcp = NULL;
580
581 /************************************************************************/
582 /* Do an evaluation of the result size. */
583 /************************************************************************/
584 if (!info) {
585 jcp = new(g) JDBConn(g, NULL);
586
587 if (jcp->Open(g) != RC_OK)
588 return NULL;
589
590 if (!maxres)
591 maxres = 256; // Estimated max number of drivers
592
593 } else
594 maxres = 0;
595
596 if (trace(1))
597 htrc("JDBCDrivers: max=%d len=%d\n", maxres, length[0]);
598
599 /************************************************************************/
600 /* Allocate the structures used to refer to the result set. */
601 /************************************************************************/
602 qrp = PlgAllocResult(g, ncol, maxres, 0, buftyp, fldtyp, length, false, true);
603
604 for (i = 0, crp = qrp->Colresp; crp; i++, crp = crp->Next) {
605 if (b[i])
606 crp->Kdata->SetNullable(true);
607
608 switch (i) {
609 case 0: crp->Name = "Name"; break;
610 case 1: crp->Name = "Version"; break;
611 case 2: crp->Name = "Compliant"; break;
612 case 3: crp->Name = "Description"; break;
613 } // endswitch
614
615 } // endfor i
616
617 /************************************************************************/
618 /* Now get the results into blocks. */
619 /************************************************************************/
620 if (!info && qrp && jcp->GetDrivers(qrp))
621 qrp = NULL;
622
623 if (!info)
624 jcp->Close();
625
626 /************************************************************************/
627 /* Return the result pointer for use by GetData routines. */
628 /************************************************************************/
629 return qrp;
630 } // end of JDBCDrivers
631
632 /***********************************************************************/
633 /* JDBConn construction/destruction. */
634 /***********************************************************************/
JDBConn(PGLOBAL g,PCSZ wrapper)635 JDBConn::JDBConn(PGLOBAL g, PCSZ wrapper) : JAVAConn(g, wrapper)
636 {
637 xqid = xuid = xid = grs = readid = fetchid = typid = errid = nullptr;
638 prepid = xpid = pcid = nullptr;
639 chrfldid = intfldid = dblfldid = fltfldid = bigfldid = nullptr;
640 objfldid = datfldid = timfldid = tspfldid = uidfldid = nullptr;
641 DiscFunc = "JdbcDisconnect";
642 m_Ncol = 0;
643 m_Aff = 0;
644 //m_Rows = 0;
645 m_Fetch = 0;
646 m_RowsetSize = 0;
647 m_Updatable = true;
648 m_Transact = false;
649 m_Scrollable = false;
650 m_Full = false;
651 m_Opened = false;
652 m_IDQuoteChar[0] = '"';
653 m_IDQuoteChar[1] = 0;
654 } // end of JDBConn
655
656 /***********************************************************************/
657 /* Search for UUID columns. */
658 /***********************************************************************/
SetUUID(PGLOBAL g,PTDBJDBC tjp)659 bool JDBConn::SetUUID(PGLOBAL g, PTDBJDBC tjp)
660 {
661 int ncol, ctyp;
662 bool brc = true;
663 PCSZ fnc = "GetColumns";
664 PCOL colp;
665 JCATPARM *cap;
666 //jint jtyp;
667 jboolean rc = false;
668 jobjectArray parms;
669 jmethodID catid = nullptr;
670
671 if (gmID(g, catid, fnc, "([Ljava/lang/String;)I"))
672 return true;
673 else if (gmID(g, intfldid, "IntField", "(ILjava/lang/String;)I"))
674 return true;
675 else if (gmID(g, readid, "ReadNext", "()I"))
676 return true;
677
678 cap = AllocCatInfo(g, JCAT_COL, tjp->Schema, tjp->TableName, NULL);
679 SQLQualifiedName name(cap);
680
681 // Build the java string array
682 parms = env->NewObjectArray(4, env->FindClass("java/lang/String"), NULL);
683 env->SetObjectArrayElement(parms, 0, env->NewStringUTF(name.ptr(2)));
684 env->SetObjectArrayElement(parms, 1, env->NewStringUTF(name.ptr(1)));
685 env->SetObjectArrayElement(parms, 2, env->NewStringUTF(name.ptr(0)));
686
687 for (colp = tjp->GetColumns(); colp; colp = colp->GetNext()) {
688 env->SetObjectArrayElement(parms, 3, env->NewStringUTF(colp->GetName()));
689 ncol = env->CallIntMethod(job, catid, parms);
690
691 if (Check(ncol)) {
692 sprintf(g->Message, "%s: %s", fnc, Msg);
693 goto err;
694 } // endif Check
695
696 rc = env->CallBooleanMethod(job, readid);
697
698 if (Check(rc)) {
699 sprintf(g->Message, "ReadNext: %s", Msg);
700 goto err;
701 } else if (rc == 0) {
702 sprintf(g->Message, "table %s does not exist", tjp->TableName);
703 goto err;
704 } // endif rc
705
706 // Should return 666 is case of error (not done yet)
707 ctyp = (int)env->CallIntMethod(job, intfldid, 5, nullptr);
708
709 //if (Check((ctyp == 666) ? -1 : 1)) {
710 // sprintf(g->Message, "Getting ctyp: %s", Msg);
711 // goto err;
712 //} // endif ctyp
713
714 if (ctyp == 1111)
715 ((PJDBCCOL)colp)->uuid = true;
716
717 } // endfor colp
718
719 // All is Ok
720 brc = false;
721
722 err:
723 // Not used anymore
724 env->DeleteLocalRef(parms);
725 return brc;
726 } // end of SetUUID
727
728 /***********************************************************************/
729 /* Utility routine. */
730 /***********************************************************************/
GetMaxValue(int n)731 int JDBConn::GetMaxValue(int n)
732 {
733 jint m;
734 jmethodID maxid = nullptr;
735
736 if (gmID(m_G, maxid, "GetMaxValue", "(I)I"))
737 return -1;
738
739 // call method
740 if (Check(m = env->CallIntMethod(job, maxid, n)))
741 htrc("GetMaxValue: %s", Msg);
742
743 return (int)m;
744 } // end of GetMaxValue
745
746 /***********************************************************************/
747 /* AddJars: add some jar file to the Class path. */
748 /***********************************************************************/
AddJars(PSTRG jpop,char sep)749 void JDBConn::AddJars(PSTRG jpop, char sep)
750 {
751 #if defined(DEVELOPMENT)
752 jpop->Append(
753 ";C:/Jconnectors/postgresql-9.4.1208.jar"
754 ";C:/Oracle/ojdbc7.jar"
755 ";C:/Apache/commons-dbcp2-2.1.1/commons-dbcp2-2.1.1.jar"
756 ";C:/Apache/commons-pool2-2.4.2/commons-pool2-2.4.2.jar"
757 ";C:/Apache/commons-logging-1.2/commons-logging-1.2.jar"
758 ";C:/Jconnectors/mysql-connector-java-6.0.2-bin.jar"
759 ";C:/Jconnectors/mariadb-java-client-2.0.1.jar"
760 ";C:/Jconnectors/sqljdbc42.jar");
761 #endif // DEVELOPMENT
762 } // end of AddJars
763
764 /***********************************************************************/
765 /* Connect: connect to a data source. */
766 /***********************************************************************/
Connect(PJPARM sop)767 bool JDBConn::Connect(PJPARM sop)
768 {
769 int irc = RC_FX;
770 bool err = false;
771 jint rc;
772 PGLOBAL& g = m_G;
773
774 /*******************************************************************/
775 /* Create or attach a JVM. */
776 /*******************************************************************/
777 if (Open(g))
778 return true;
779
780 if (!sop) // DRIVER catalog table
781 return false;
782
783 jmethodID cid = nullptr;
784
785 if (gmID(g, cid, "JdbcConnect", "([Ljava/lang/String;IZ)I"))
786 return true;
787
788 // Build the java string array
789 jobjectArray parms = env->NewObjectArray(4, // constructs java array of 4
790 env->FindClass("java/lang/String"), NULL); // Strings
791
792 m_Scrollable = sop->Scrollable;
793 m_RowsetSize = sop->Fsize;
794 //m_LoginTimeout = sop->Cto;
795 //m_QueryTimeout = sop->Qto;
796 //m_UseCnc = sop->UseCnc;
797
798 // change some elements
799 if (sop->Driver)
800 env->SetObjectArrayElement(parms, 0, env->NewStringUTF(sop->Driver));
801
802 if (sop->Url)
803 env->SetObjectArrayElement(parms, 1, env->NewStringUTF(sop->Url));
804
805 if (sop->User)
806 env->SetObjectArrayElement(parms, 2, env->NewStringUTF(sop->User));
807
808 if (sop->Pwd)
809 env->SetObjectArrayElement(parms, 3, env->NewStringUTF(sop->Pwd));
810
811 // call method
812 rc = env->CallIntMethod(job, cid, parms, m_RowsetSize, m_Scrollable);
813 err = Check(rc);
814 env->DeleteLocalRef(parms); // Not used anymore
815
816 if (err) {
817 sprintf(g->Message, "Connecting: %s rc=%d", Msg, (int)rc);
818 return true;
819 } // endif Msg
820
821 jmethodID qcid = nullptr;
822
823 if (!gmID(g, qcid, "GetQuoteString", "()Ljava/lang/String;")) {
824 jstring s = (jstring)env->CallObjectMethod(job, qcid);
825
826 if (s != nullptr) {
827 char *qch = GetUTFString(s);
828 m_IDQuoteChar[0] = *qch;
829 } else {
830 s = (jstring)env->CallObjectMethod(job, errid);
831 Msg = GetUTFString(s);
832 } // endif s
833
834 } // endif qcid
835
836 if (gmID(g, typid, "ColumnType", "(ILjava/lang/String;)I"))
837 return true;
838 else
839 m_Connected = true;
840
841 return false;
842 } // end of Connect
843
844
845 /***********************************************************************/
846 /* Execute an SQL command. */
847 /***********************************************************************/
ExecuteCommand(PCSZ sql)848 int JDBConn::ExecuteCommand(PCSZ sql)
849 {
850 int rc;
851 jint n;
852 jstring qry;
853 PGLOBAL& g = m_G;
854
855 // Get the methods used to execute a query and get the result
856 if (gmID(g, xid, "Execute", "(Ljava/lang/String;)I") ||
857 gmID(g, grs, "GetResult", "()I"))
858 return RC_FX;
859
860 qry = env->NewStringUTF(sql);
861 n = env->CallIntMethod(job, xid, qry);
862 env->DeleteLocalRef(qry);
863
864 if (Check(n)) {
865 sprintf(g->Message, "Execute: %s", Msg);
866 return RC_FX;
867 } // endif n
868
869 m_Ncol = env->CallIntMethod(job, grs);
870
871 if (Check(m_Ncol)) {
872 sprintf(g->Message, "GetResult: %s", Msg);
873 rc = RC_FX;
874 } else if (m_Ncol) {
875 strcpy(g->Message, "Result set column number");
876 rc = RC_OK; // A result set was returned
877 } else {
878 m_Aff = (int)n; // Affected rows
879 strcpy(g->Message, "Affected rows");
880 rc = RC_NF;
881 } // endif ncol
882
883 return rc;
884 } // end of ExecuteCommand
885
886 /***********************************************************************/
887 /* Fetch next row. */
888 /***********************************************************************/
Fetch(int pos)889 int JDBConn::Fetch(int pos)
890 {
891 jint rc = JNI_ERR;
892 PGLOBAL& g = m_G;
893
894 if (m_Full) // Result set has one row
895 return 1;
896
897 if (pos) {
898 if (!m_Scrollable) {
899 strcpy(g->Message, "Cannot fetch(pos) if FORWARD ONLY");
900 return rc;
901 } else if (gmID(m_G, fetchid, "Fetch", "(I)Z"))
902 return rc;
903
904 if (env->CallBooleanMethod(job, fetchid, pos))
905 rc = m_Rows;
906
907 } else {
908 if (gmID(g, readid, "ReadNext", "()I"))
909 return rc;
910
911 rc = env->CallBooleanMethod(job, readid);
912
913 if (!Check(rc)) {
914 if (rc == 0)
915 m_Full = (m_Fetch == 1);
916 else
917 m_Fetch++;
918
919 m_Rows += (int)rc;
920 } else
921 sprintf(g->Message, "Fetch: %s", Msg);
922
923 } // endif pos
924
925 return (int)rc;
926 } // end of Fetch
927
928 /***********************************************************************/
929 /* Restart from beginning of result set */
930 /***********************************************************************/
Rewind(PCSZ sql)931 int JDBConn::Rewind(PCSZ sql)
932 {
933 int rbuf = -1;
934
935 if (m_Full)
936 rbuf = m_Rows; // No need to "rewind"
937 else if (m_Scrollable) {
938 if (gmID(m_G, fetchid, "Fetch", "(I)Z"))
939 return -1;
940
941 (void) env->CallBooleanMethod(job, fetchid, 0);
942
943 rbuf = m_Rows;
944 } else if (ExecuteCommand(sql) != RC_FX)
945 rbuf = 0;
946
947 return rbuf;
948 } // end of Rewind
949
950 /***********************************************************************/
951 /* Retrieve and set the column value from the result set. */
952 /***********************************************************************/
SetColumnValue(int rank,PSZ name,PVAL val)953 void JDBConn::SetColumnValue(int rank, PSZ name, PVAL val)
954 {
955 const char *field;
956 PGLOBAL& g = m_G;
957 jint ctyp;
958 jstring cn, jn = nullptr;
959 jobject jb = nullptr;
960
961 if (rank == 0)
962 if (!name || (jn = env->NewStringUTF(name)) == nullptr) {
963 sprintf(g->Message, "Fail to allocate jstring %s", SVP(name));
964 throw (int)TYPE_AM_JDBC;
965 } // endif name
966
967 // Returns 666 is case of error
968 ctyp = env->CallIntMethod(job, typid, rank, jn);
969
970 if (Check((ctyp == 666) ? -1 : 1)) {
971 sprintf(g->Message, "Getting ctyp: %s", Msg);
972 throw (int)TYPE_AM_JDBC;
973 } // endif Check
974
975 if (val->GetNullable())
976 if (!gmID(g, objfldid, "ObjectField", "(ILjava/lang/String;)Ljava/lang/Object;")) {
977 jb = env->CallObjectMethod(job, objfldid, (jint)rank, jn);
978
979 if (Check(0)) {
980 sprintf(g->Message, "Getting jp: %s", Msg);
981 throw (int)TYPE_AM_JDBC;
982 } // endif Check
983
984 if (jb == nullptr) {
985 val->Reset();
986 val->SetNull(true);
987 goto chk;
988 } // endif job
989
990 } // endif objfldid
991
992 switch (ctyp) {
993 case 12: // VARCHAR
994 case -9: // NVARCHAR
995 case -1: // LONGVARCHAR, TEXT
996 case 1: // CHAR
997 case -15: // NCHAR
998 case -16: // LONGNVARCHAR, NTEXT
999 case 3: // DECIMAL
1000 case -8: // ROWID
1001 if (jb && ctyp != 3)
1002 cn = (jstring)jb;
1003 else if (!gmID(g, chrfldid, "StringField", "(ILjava/lang/String;)Ljava/lang/String;"))
1004 cn = (jstring)env->CallObjectMethod(job, chrfldid, (jint)rank, jn);
1005 else
1006 cn = nullptr;
1007
1008 if (cn) {
1009 field = GetUTFString(cn);
1010 val->SetValue_psz((PSZ)field);
1011 } else
1012 val->Reset();
1013
1014 break;
1015 case 4: // INTEGER
1016 case 5: // SMALLINT
1017 case -6: // TINYINT
1018 case 16: // BOOLEAN
1019 case -7: // BIT
1020 if (!gmID(g, intfldid, "IntField", "(ILjava/lang/String;)I"))
1021 val->SetValue((int)env->CallIntMethod(job, intfldid, rank, jn));
1022 else
1023 val->Reset();
1024
1025 break;
1026 case 8: // DOUBLE
1027 case 2: // NUMERIC
1028 //case 3: // DECIMAL
1029 if (!gmID(g, dblfldid, "DoubleField", "(ILjava/lang/String;)D"))
1030 val->SetValue((double)env->CallDoubleMethod(job, dblfldid, rank, jn));
1031 else
1032 val->Reset();
1033
1034 break;
1035 case 7: // REAL
1036 case 6: // FLOAT
1037 if (!gmID(g, fltfldid, "FloatField", "(ILjava/lang/String;)F"))
1038 val->SetValue((float)env->CallFloatMethod(job, fltfldid, rank, jn));
1039 else
1040 val->Reset();
1041
1042 break;
1043 case 91: // DATE
1044 if (!gmID(g, datfldid, "DateField", "(ILjava/lang/String;)I")) {
1045 val->SetValue((int)env->CallIntMethod(job, datfldid, (jint)rank, jn));
1046 } else
1047 val->Reset();
1048
1049 break;
1050 case 92: // TIME
1051 if (!gmID(g, timfldid, "TimeField", "(ILjava/lang/String;)I")) {
1052 val->SetValue((int)env->CallIntMethod(job, timfldid, (jint)rank, jn));
1053 } else
1054 val->Reset();
1055
1056 break;
1057 case 93: // TIMESTAMP
1058 if (!gmID(g, tspfldid, "TimestampField", "(ILjava/lang/String;)I")) {
1059 val->SetValue((int)env->CallIntMethod(job, tspfldid, (jint)rank, jn));
1060 } else
1061 val->Reset();
1062
1063 break;
1064 case -5: // BIGINT
1065 if (!gmID(g, bigfldid, "BigintField", "(ILjava/lang/String;)J"))
1066 val->SetValue((long long)env->CallLongMethod(job, bigfldid, (jint)rank, jn));
1067 else
1068 val->Reset();
1069
1070 break;
1071 /* case java.sql.Types.SMALLINT:
1072 System.out.print(jdi.IntField(i));
1073 break;
1074 case java.sql.Types.BOOLEAN:
1075 System.out.print(jdi.BooleanField(i)); */
1076 case 1111: // UUID
1077 if (!gmID(g, uidfldid, "UuidField", "(ILjava/lang/String;)Ljava/lang/String;"))
1078 cn = (jstring)env->CallObjectMethod(job, uidfldid, (jint)rank, jn);
1079 else
1080 cn = nullptr;
1081
1082 if (cn) {
1083 val->SetValue_psz((PSZ)GetUTFString(cn));
1084 } else
1085 val->Reset();
1086
1087 break;
1088 case 0: // NULL
1089 val->SetNull(true);
1090 // passthru
1091 default:
1092 val->Reset();
1093 } // endswitch Type
1094
1095 chk:
1096 if (Check()) {
1097 if (rank == 0)
1098 env->DeleteLocalRef(jn);
1099
1100 sprintf(g->Message, "SetColumnValue: %s rank=%d ctyp=%d", Msg, rank, (int)ctyp);
1101 throw (int)TYPE_AM_JDBC;
1102 } // endif Check
1103
1104 if (rank == 0)
1105 env->DeleteLocalRef(jn);
1106
1107 } // end of SetColumnValue
1108
1109 /***********************************************************************/
1110 /* Prepare an SQL statement for insert. */
1111 /***********************************************************************/
PrepareSQL(PCSZ sql)1112 bool JDBConn::PrepareSQL(PCSZ sql)
1113 {
1114 bool b = true;
1115 PGLOBAL& g = m_G;
1116
1117 if (!gmID(g, prepid, "CreatePrepStmt", "(Ljava/lang/String;)I")) {
1118 // Create the prepared statement
1119 jstring qry = env->NewStringUTF(sql);
1120
1121 if (Check(env->CallBooleanMethod(job, prepid, qry)))
1122 sprintf(g->Message, "CreatePrepStmt: %s", Msg);
1123 else
1124 b = false;
1125
1126 env->DeleteLocalRef(qry);
1127 } // endif prepid
1128
1129 return b;
1130 } // end of PrepareSQL
1131
1132 /***********************************************************************/
1133 /* Execute an SQL query that returns a result set. */
1134 /***********************************************************************/
ExecuteQuery(PCSZ sql)1135 int JDBConn::ExecuteQuery(PCSZ sql)
1136 {
1137 int rc = RC_FX;
1138 jint ncol;
1139 jstring qry;
1140 PGLOBAL& g = m_G;
1141
1142 // Get the methods used to execute a query and get the result
1143 if (!gmID(g, xqid, "ExecuteQuery", "(Ljava/lang/String;)I")) {
1144 qry = env->NewStringUTF(sql);
1145 ncol = env->CallIntMethod(job, xqid, qry);
1146
1147 if (!Check(ncol)) {
1148 m_Ncol = (int)ncol;
1149 m_Aff = 0; // Affected rows
1150 rc = RC_OK;
1151 } else
1152 sprintf(g->Message, "ExecuteQuery: %s", Msg);
1153
1154 env->DeleteLocalRef(qry);
1155 } // endif xqid
1156
1157 return rc;
1158 } // end of ExecuteQuery
1159
1160 /***********************************************************************/
1161 /* Execute an SQL query and get the affected rows. */
1162 /***********************************************************************/
ExecuteUpdate(PCSZ sql)1163 int JDBConn::ExecuteUpdate(PCSZ sql)
1164 {
1165 int rc = RC_FX;
1166 jint n;
1167 jstring qry;
1168 PGLOBAL& g = m_G;
1169
1170 // Get the methods used to execute a query and get the affected rows
1171 if (!gmID(g, xuid, "ExecuteUpdate", "(Ljava/lang/String;)I")) {
1172 qry = env->NewStringUTF(sql);
1173 n = env->CallIntMethod(job, xuid, qry);
1174
1175 if (!Check(n)) {
1176 m_Ncol = 0;
1177 m_Aff = (int)n; // Affected rows
1178 rc = RC_OK;
1179 } else
1180 sprintf(g->Message, "ExecuteUpdate: %s n=%d", Msg, n);
1181
1182 env->DeleteLocalRef(qry);
1183 } // endif xuid
1184
1185 return rc;
1186 } // end of ExecuteUpdate
1187
1188 /***********************************************************************/
1189 /* Get the number of lines of the result set. */
1190 /***********************************************************************/
GetResultSize(PCSZ sql,PCOL colp)1191 int JDBConn::GetResultSize(PCSZ sql, PCOL colp)
1192 {
1193 int rc;
1194
1195 if ((rc = ExecuteQuery(sql)) != RC_OK)
1196 return -1;
1197
1198 if ((rc = Fetch()) > 0) {
1199 try {
1200 SetColumnValue(1, NULL, colp->GetValue());
1201 } catch (...) {
1202 return -4;
1203 } // end catch
1204
1205 } else
1206 return -2;
1207
1208 if ((rc = Fetch()) != 0)
1209 return -3;
1210
1211 m_Full = false;
1212 return colp->GetIntValue();
1213 } // end of GetResultSize
1214
1215 /***********************************************************************/
1216 /* Execute a prepared statement. */
1217 /***********************************************************************/
ExecuteSQL(void)1218 int JDBConn::ExecuteSQL(void)
1219 {
1220 int rc = RC_FX;
1221 PGLOBAL& g = m_G;
1222
1223 // Get the methods used to execute a prepared statement
1224 if (!gmID(g, xpid, "ExecutePrep", "()I")) {
1225 jint n = env->CallIntMethod(job, xpid);
1226
1227 if (n == -3)
1228 strcpy(g->Message, "SQL statement is not prepared");
1229 else if (Check(n))
1230 sprintf(g->Message, "ExecutePrep: %s", Msg);
1231 else {
1232 m_Aff = (int)n;
1233 rc = RC_OK;
1234 } // endswitch n
1235
1236 } // endif xpid
1237
1238 return rc;
1239 } // end of ExecuteSQL
1240
1241 /***********************************************************************/
1242 /* Set a parameter for inserting. */
1243 /***********************************************************************/
SetParam(JDBCCOL * colp)1244 bool JDBConn::SetParam(JDBCCOL *colp)
1245 {
1246 PGLOBAL& g = m_G;
1247 bool rc = false;
1248 PVAL val = colp->GetValue();
1249 jint n, jrc = 0, i = (jint)colp->GetRank();
1250 jshort s;
1251 jlong lg;
1252 //jfloat f;
1253 jdouble d;
1254 jclass dat;
1255 jobject datobj;
1256 jstring jst = nullptr;
1257 jmethodID dtc, setid = nullptr;
1258
1259 if (val->GetNullable() && val->IsNull()) {
1260 if (gmID(g, setid, "SetNullParm", "(II)I"))
1261 return true;
1262
1263 jrc = env->CallIntMethod(job, setid, i,
1264 (colp->uuid ? 1111 : (jint)GetJDBCType(val->GetType())));
1265 } else if (colp->uuid) {
1266 if (gmID(g, setid, "SetUuidParm", "(ILjava/lang/String;)V"))
1267 return true;
1268
1269 jst = env->NewStringUTF(val->GetCharValue());
1270 env->CallVoidMethod(job, setid, i, jst);
1271 } else switch (val->GetType()) {
1272 case TYPE_STRING:
1273 if (gmID(g, setid, "SetStringParm", "(ILjava/lang/String;)V"))
1274 return true;
1275
1276 jst = env->NewStringUTF(val->GetCharValue());
1277 env->CallVoidMethod(job, setid, i, jst);
1278 break;
1279 case TYPE_INT:
1280 if (gmID(g, setid, "SetIntParm", "(II)V"))
1281 return true;
1282
1283 n = (jint)val->GetIntValue();
1284 env->CallVoidMethod(job, setid, i, n);
1285 break;
1286 case TYPE_TINY:
1287 case TYPE_SHORT:
1288 if (gmID(g, setid, "SetShortParm", "(IS)V"))
1289 return true;
1290
1291 s = (jshort)val->GetShortValue();
1292 env->CallVoidMethod(job, setid, i, s);
1293 break;
1294 case TYPE_BIGINT:
1295 if (gmID(g, setid, "SetBigintParm", "(IJ)V"))
1296 return true;
1297
1298 lg = (jlong)val->GetBigintValue();
1299 env->CallVoidMethod(job, setid, i, lg);
1300 break;
1301 case TYPE_DOUBLE:
1302 case TYPE_DECIM:
1303 if (gmID(g, setid, "SetDoubleParm", "(ID)V"))
1304 return true;
1305
1306 d = (jdouble)val->GetFloatValue();
1307 env->CallVoidMethod(job, setid, i, d);
1308 break;
1309 case TYPE_DATE:
1310 if ((dat = env->FindClass("java/sql/Timestamp")) == nullptr) {
1311 strcpy(g->Message, "Cannot find Timestamp class");
1312 return true;
1313 } else if (!(dtc = env->GetMethodID(dat, "<init>", "(J)V"))) {
1314 strcpy(g->Message, "Cannot find Timestamp class constructor");
1315 return true;
1316 } // endif's
1317
1318 lg = (jlong)val->GetBigintValue() * 1000;
1319
1320 if ((datobj = env->NewObject(dat, dtc, lg)) == nullptr) {
1321 strcpy(g->Message, "Cannot make Timestamp object");
1322 return true;
1323 } else if (gmID(g, setid, "SetTimestampParm", "(ILjava/sql/Timestamp;)V"))
1324 return true;
1325
1326 env->CallVoidMethod(job, setid, i, datobj);
1327 break;
1328 default:
1329 sprintf(g->Message, "Parm type %d not supported", val->GetType());
1330 return true;
1331 } // endswitch Type
1332
1333 if (Check(jrc)) {
1334 sprintf(g->Message, "SetParam: col=%s msg=%s", colp->GetName(), Msg);
1335 rc = true;
1336 } // endif msg
1337
1338 if (jst)
1339 env->DeleteLocalRef(jst);
1340
1341 return rc;
1342 } // end of SetParam
1343
1344 /***********************************************************************/
1345 /* Get the list of Drivers and set it in qrp. */
1346 /***********************************************************************/
GetDrivers(PQRYRES qrp)1347 bool JDBConn::GetDrivers(PQRYRES qrp)
1348 {
1349 PSZ sval;
1350 int i, n, size;
1351 PCOLRES crp;
1352 jstring js;
1353 jmethodID gdid = nullptr;
1354
1355 if (gmID(m_G, gdid, "GetDrivers", "([Ljava/lang/String;I)I"))
1356 return true;
1357
1358 // Build the java string array
1359 jobjectArray s = env->NewObjectArray(4 * qrp->Maxres,
1360 env->FindClass("java/lang/String"), NULL);
1361
1362 size = env->CallIntMethod(job, gdid, s, qrp->Maxres);
1363
1364 for (i = 0, n = 0; i < size; i++) {
1365 crp = qrp->Colresp;
1366 js = (jstring)env->GetObjectArrayElement(s, n++);
1367 sval = GetUTFString(js);
1368 crp->Kdata->SetValue(sval, i);
1369 crp = crp->Next;
1370 js = (jstring)env->GetObjectArrayElement(s, n++);
1371 sval = GetUTFString(js);
1372 crp->Kdata->SetValue(sval, i);
1373 crp = crp->Next;
1374 js = (jstring)env->GetObjectArrayElement(s, n++);
1375 sval = GetUTFString(js);
1376 crp->Kdata->SetValue(sval, i);
1377 crp = crp->Next;
1378 js = (jstring)env->GetObjectArrayElement(s, n++);
1379 sval = GetUTFString(js);
1380 crp->Kdata->SetValue(sval, i);
1381 } // endfor i
1382
1383 // Not used anymore
1384 env->DeleteLocalRef(s);
1385
1386 qrp->Nblin = size;
1387 return false;
1388 } // end of GetDrivers
1389
1390 /**************************************************************************/
1391 /* GetMetaData: constructs the result blocks containing the */
1392 /* description of all the columns of an SQL command. */
1393 /**************************************************************************/
GetMetaData(PGLOBAL g,PCSZ src)1394 PQRYRES JDBConn::GetMetaData(PGLOBAL g, PCSZ src)
1395 {
1396 static int buftyp[] = {TYPE_STRING, TYPE_INT, TYPE_INT,
1397 TYPE_INT, TYPE_INT};
1398 static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_PREC,
1399 FLD_SCALE, FLD_NULL };
1400 static unsigned int length[] = {0, 6, 10, 6, 6};
1401 const char *name;
1402 int len, qcol = 5;
1403 PQRYRES qrp = NULL;
1404 PCOLRES crp;
1405 ushort i;
1406 jint *n = nullptr;
1407 jstring label;
1408 jmethodID colid = nullptr;
1409 int rc = ExecuteCommand(src);
1410
1411 if (rc == RC_NF) {
1412 strcpy(g->Message, "Srcdef is not returning a result set");
1413 return NULL;
1414 } else if ((rc) == RC_FX) {
1415 return NULL;
1416 } else if (m_Ncol == 0) {
1417 strcpy(g->Message, "Invalid Srcdef");
1418 return NULL;
1419 } // endif's
1420
1421 if (gmID(g, colid, "ColumnDesc", "(I[I)Ljava/lang/String;"))
1422 return NULL;
1423
1424 // Get max column name length
1425 len = GetMaxValue(5);
1426 length[0] = (len > 0) ? len + 1 : 128;
1427
1428 /************************************************************************/
1429 /* Allocate the structures used to refer to the result set. */
1430 /************************************************************************/
1431 if (!(qrp = PlgAllocResult(g, qcol, m_Ncol, IDS_COLUMNS + 3,
1432 buftyp, fldtyp, length, false, true)))
1433 return NULL;
1434
1435 // Some columns must be renamed
1436 for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next)
1437 switch (++i) {
1438 case 3: crp->Name = "Precision"; break;
1439 case 4: crp->Name = "Scale"; break;
1440 case 5: crp->Name = "Nullable"; break;
1441 } // endswitch i
1442
1443 // Build the java int array
1444 jintArray val = env->NewIntArray(4);
1445
1446 if (val == nullptr) {
1447 strcpy(m_G->Message, "Cannot allocate jint array");
1448 return NULL;
1449 } // endif colid
1450
1451 /************************************************************************/
1452 /* Now get the results into blocks. */
1453 /************************************************************************/
1454 for (i = 0; i < m_Ncol; i++) {
1455 if (!(label = (jstring)env->CallObjectMethod(job, colid, i + 1, val))) {
1456 if (Check())
1457 sprintf(g->Message, "ColumnDesc: %s", Msg);
1458 else
1459 strcpy(g->Message, "No result metadata");
1460
1461 env->ReleaseIntArrayElements(val, n, 0);
1462 return NULL;
1463 } // endif label
1464
1465 name = GetUTFString(label);
1466 crp = qrp->Colresp; // Column_Name
1467 crp->Kdata->SetValue((char*)name, i);
1468 n = env->GetIntArrayElements(val, 0);
1469 crp = crp->Next; // Data_Type
1470 crp->Kdata->SetValue((int)n[0], i);
1471 crp = crp->Next; // Precision (length)
1472 crp->Kdata->SetValue((int)n[1], i);
1473 crp = crp->Next; // Scale
1474 crp->Kdata->SetValue((int)n[2], i);
1475 crp = crp->Next; // Nullable
1476 crp->Kdata->SetValue((int)n[3], i);
1477 qrp->Nblin++;
1478 } // endfor i
1479
1480 /* Cleanup */
1481 env->ReleaseIntArrayElements(val, n, 0);
1482
1483 /************************************************************************/
1484 /* Return the result pointer for use by GetData routines. */
1485 /************************************************************************/
1486 return qrp;
1487 } // end of GetMetaData
1488
1489 /***********************************************************************/
1490 /* Allocate recset and call SQLTables, SQLColumns or SQLPrimaryKeys. */
1491 /***********************************************************************/
GetCatInfo(JCATPARM * cap)1492 int JDBConn::GetCatInfo(JCATPARM *cap)
1493 {
1494 PGLOBAL& g = m_G;
1495 // void *buffer;
1496 int i, ncol;
1497 PCSZ fnc = "Unknown";
1498 uint n;
1499 short len, tp;
1500 PQRYRES qrp = cap->Qrp;
1501 PCOLRES crp;
1502 jboolean rc = false;
1503 // HSTMT hstmt = NULL;
1504 // SQLLEN *vl, *vlen = NULL;
1505 PVAL *pval = NULL;
1506 char* *pbuf = NULL;
1507 jobjectArray parms;
1508 jmethodID catid = nullptr;
1509
1510 if (qrp->Maxres <= 0)
1511 return 0; // 0-sized result"
1512
1513 SQLQualifiedName name(cap);
1514
1515 // Build the java string array
1516 parms = env->NewObjectArray(4, env->FindClass("java/lang/String"), NULL);
1517 env->SetObjectArrayElement(parms, 0, env->NewStringUTF(name.ptr(2)));
1518 env->SetObjectArrayElement(parms, 1, env->NewStringUTF(name.ptr(1)));
1519 env->SetObjectArrayElement(parms, 2, env->NewStringUTF(name.ptr(0)));
1520 env->SetObjectArrayElement(parms, 3, env->NewStringUTF((const char*)cap->Pat));
1521
1522 // Now do call the proper JDBC API
1523 switch (cap->Id) {
1524 case JCAT_COL:
1525 fnc = "GetColumns";
1526 break;
1527 case JCAT_TAB:
1528 fnc = "GetTables";
1529 break;
1530 #if 0
1531 case JCAT_KEY:
1532 fnc = "SQLPrimaryKeys";
1533 rc = SQLPrimaryKeys(hstmt, name.ptr(2), name.length(2),
1534 name.ptr(1), name.length(1),
1535 name.ptr(0), name.length(0));
1536 break;
1537 #endif // 0
1538 default:
1539 sprintf(g->Message, "Invalid SQL function id");
1540 return -1;
1541 } // endswitch infotype
1542
1543 if (gmID(g, catid, fnc, "([Ljava/lang/String;)I"))
1544 return -1;
1545
1546 // call method
1547 ncol = env->CallIntMethod(job, catid, parms);
1548
1549 if (Check(ncol)) {
1550 sprintf(g->Message, "%s: %s", fnc, Msg);
1551 env->DeleteLocalRef(parms);
1552 return -1;
1553 } // endif Check
1554
1555 // Not used anymore
1556 env->DeleteLocalRef(parms);
1557
1558 if (trace(1))
1559 htrc("Method %s returned %d columns\n", fnc, ncol);
1560
1561 // n because we no more ignore the first column
1562 if ((n = qrp->Nbcol) > (uint)ncol) {
1563 strcpy(g->Message, MSG(COL_NUM_MISM));
1564 return -1;
1565 } // endif n
1566
1567 // Unconditional to handle STRBLK's
1568 pval = (PVAL *)PlugSubAlloc(g, NULL, n * sizeof(PVAL));
1569 // vlen = (SQLLEN *)PlugSubAlloc(g, NULL, n * sizeof(SQLLEN));
1570 pbuf = (char**)PlugSubAlloc(g, NULL, n * sizeof(char*));
1571
1572 // Prepare retrieving column values
1573 for (n = 0, crp = qrp->Colresp; crp; crp = crp->Next) {
1574 if (!(tp = GetJDBCType(crp->Type))) {
1575 sprintf(g->Message, MSG(INV_COLUMN_TYPE), crp->Type, crp->Name);
1576 return -1;
1577 } // endif tp
1578
1579 if (!(len = GetTypeSize(crp->Type, crp->Length))) {
1580 len = 255; // for STRBLK's
1581 ((STRBLK*)crp->Kdata)->SetSorted(true);
1582 } // endif len
1583
1584 pval[n] = AllocateValue(g, crp->Type, len);
1585 pval[n]->SetNullable(true);
1586
1587 if (crp->Type == TYPE_STRING) {
1588 pbuf[n] = (char*)PlugSubAlloc(g, NULL, len);
1589 // buffer = pbuf[n];
1590 } // endif Type
1591 // } else
1592 // buffer = pval[n]->GetTo_Val();
1593
1594 n++;
1595 } // endfor n
1596
1597 // Now fetch the result
1598 for (i = 0; i < qrp->Maxres; i++) {
1599 if (Check(rc = Fetch(0))) {
1600 sprintf(g->Message, "Fetch: %s", Msg);
1601 return -1;
1602 } if (rc == 0) {
1603 if (trace(1))
1604 htrc("End of fetches i=%d\n", i);
1605
1606 break;
1607 } // endif rc
1608
1609 for (n = 0, crp = qrp->Colresp; crp; n++, crp = crp->Next) {
1610 SetColumnValue(n + 1, nullptr, pval[n]);
1611 crp->Kdata->SetValue(pval[n], i);
1612 } // endfor n
1613
1614 } // endfor i
1615
1616 if (rc > 0)
1617 qrp->Truncated = true;
1618
1619 return i;
1620 } // end of GetCatInfo
1621
1622 /***********************************************************************/
1623 /* Allocate a CONNECT result structure from the JDBC result. */
1624 /***********************************************************************/
AllocateResult(PGLOBAL g,PTDB tdbp)1625 PQRYRES JDBConn::AllocateResult(PGLOBAL g, PTDB tdbp)
1626 {
1627 bool uns;
1628 PCOL colp;
1629 PCOLRES *pcrp, crp;
1630 PQRYRES qrp;
1631
1632 if (!m_Rows) {
1633 strcpy(g->Message, "Void result");
1634 return NULL;
1635 } // endif m_Rows
1636
1637 /*********************************************************************/
1638 /* Allocate the result storage for future retrieval. */
1639 /*********************************************************************/
1640 qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
1641 pcrp = &qrp->Colresp;
1642 qrp->Continued = FALSE;
1643 qrp->Truncated = FALSE;
1644 qrp->Info = FALSE;
1645 qrp->Suball = TRUE;
1646 qrp->BadLines = 0;
1647 qrp->Maxsize = m_Rows;
1648 qrp->Maxres = m_Rows;
1649 qrp->Nbcol = 0;
1650 qrp->Nblin = 0;
1651 qrp->Cursor = 0;
1652
1653 for (colp = tdbp->GetColumns(); colp; colp = colp->GetNext())
1654 if (!colp->IsSpecial()) {
1655 *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
1656 crp = *pcrp;
1657 pcrp = &crp->Next;
1658 memset(crp, 0, sizeof(COLRES));
1659 crp->Ncol = ++qrp->Nbcol;
1660 crp->Name = colp->GetName();
1661 crp->Type = colp->GetResultType();
1662 crp->Prec = colp->GetScale();
1663 crp->Length = colp->GetLength();
1664 crp->Clen = colp->GetValue()->GetClen();
1665 uns = colp->IsUnsigned();
1666
1667 if (!(crp->Kdata = AllocValBlock(g, NULL, crp->Type, m_Rows,
1668 crp->Clen, 0, FALSE, TRUE, uns))) {
1669 sprintf(g->Message, MSG(INV_RESULT_TYPE),
1670 GetFormatType(crp->Type));
1671 return NULL;
1672 } // endif Kdata
1673
1674 if (!colp->IsNullable())
1675 crp->Nulls = NULL;
1676 else {
1677 crp->Nulls = (char*)PlugSubAlloc(g, NULL, m_Rows);
1678 memset(crp->Nulls, ' ', m_Rows);
1679 } // endelse Nullable
1680
1681 ((EXTCOL*)colp)->SetCrp(crp);
1682 } // endif colp
1683
1684 *pcrp = NULL;
1685 return qrp;
1686 } // end of AllocateResult
1687