1 /******************************************************************************
2 *
3 * Project: OpenGIS Simple Features Reference Implementation
4 * Purpose: Implements OGRMDBJavaEnv class.
5 * Author: Even Rouault, <even dot rouault at spatialys.com>
6 *
7 ******************************************************************************
8 * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ****************************************************************************/
28
29 #include "ogr_mdb.h"
30 #include "cpl_multiproc.h"
31
32 CPL_CVSID("$Id: ogrmdbjackcess.cpp 355b41831cd2685c85d1aabe5b95665a2c6e99b7 2019-06-19 17:07:04 +0200 Even Rouault $")
33
34 #if JVM_LIB_DLOPEN
35 #include <limits.h>
36 #include <stdio.h>
37 #endif
38
39 static JavaVM *jvm_static = nullptr;
40 static CPLMutex* hMutex = nullptr;
41
42 /************************************************************************/
43 /* OGRMDBJavaEnv() */
44 /************************************************************************/
45
OGRMDBJavaEnv()46 OGRMDBJavaEnv::OGRMDBJavaEnv()
47 {
48 }
49
50 /************************************************************************/
51 /* ~OGRMDBJavaEnv() */
52 /************************************************************************/
53
~OGRMDBJavaEnv()54 OGRMDBJavaEnv::~OGRMDBJavaEnv()
55 {
56 if (jvm)
57 {
58 env->DeleteLocalRef(byteArray_class);
59
60 env->DeleteLocalRef(file_class);
61 env->DeleteLocalRef(database_class);
62
63 env->DeleteLocalRef(table_class);
64
65 env->DeleteLocalRef(column_class);
66
67 env->DeleteLocalRef(datatype_class);
68
69 env->DeleteLocalRef(list_class);
70
71 env->DeleteLocalRef(set_class);
72
73 env->DeleteLocalRef(map_class);
74
75 env->DeleteLocalRef(iterator_class);
76
77 env->DeleteLocalRef(object_class);
78
79 env->DeleteLocalRef(boolean_class);
80 env->DeleteLocalRef(byte_class);
81 env->DeleteLocalRef(short_class);
82 env->DeleteLocalRef(integer_class);
83 env->DeleteLocalRef(float_class);
84 env->DeleteLocalRef(double_class);
85
86 /*if (!bCalledFromJava)
87 {
88 CPLDebug("MDB", "Destroying JVM");
89 int ret = jvm->DestroyJavaVM();
90 CPLDebug("MDB", "ret=%d", ret);
91 }*/
92 }
93 }
94
95 #define CHECK(x, y) do {x = y; if (!x) { \
96 CPLError(CE_Failure, CPLE_AppDefined, #y " failed"); \
97 return FALSE;} } while( false )
98
99 /************************************************************************/
100 /* CleanupMutex() */
101 /************************************************************************/
102
CleanupMutex()103 void OGRMDBJavaEnv::CleanupMutex()
104 {
105 if( hMutex )
106 CPLDestroyMutex(hMutex);
107 hMutex = nullptr;
108 }
109
110 /************************************************************************/
111 /* InitIfNeeded() */
112 /************************************************************************/
113
InitIfNeeded()114 int OGRMDBJavaEnv::InitIfNeeded()
115 {
116 GIntBig nCurPID = CPLGetPID();
117 if( env == nullptr || bCalledFromJava || nLastPID != nCurPID )
118 {
119 nLastPID = nCurPID;
120 return Init();
121 }
122 return env != nullptr;
123 }
124
125 /************************************************************************/
126 /* Init() */
127 /************************************************************************/
128
Init()129 int OGRMDBJavaEnv::Init()
130 {
131 CPLMutexHolderD(&hMutex);
132
133 jvm = nullptr;
134 env = nullptr;
135
136 if (jvm_static == nullptr)
137 {
138 JavaVM* vmBuf[1];
139 jsize nVMs;
140 int ret = 0;
141
142 #if JVM_LIB_DLOPEN
143 # if defined(__APPLE__) && defined(__MACH__)
144 # define SO_EXT "dylib"
145 # else
146 # define SO_EXT "so"
147 # endif
148 const char *jvmLibPtr = "libjvm." SO_EXT;
149 char jvmLib[PATH_MAX];
150
151 /* libjvm.so's location is hard to predict so
152 ${JAVA_HOME}/bin/java -XshowSettings is executed to find
153 its location. If JAVA_HOME is not set then java is executed
154 from the PATH instead. This is POSIX-compliant code. */
155 FILE *javaCmd = popen("\"${JAVA_HOME}${JAVA_HOME:+/bin/}java\" -XshowSettings 2>&1 | grep 'sun.boot.library.path'", "r");
156
157 if (javaCmd != nullptr)
158 {
159 char szTmp[PATH_MAX];
160 size_t javaCmdRead = fread(szTmp, 1, sizeof(szTmp), javaCmd);
161 ret = pclose(javaCmd);
162
163 if (ret == 0 && javaCmdRead >= 2)
164 {
165 /* Chomp the new line */
166 szTmp[javaCmdRead - 1] = '\0';
167 const char* pszPtr = strchr(szTmp, '=');
168 if( pszPtr )
169 {
170 pszPtr ++;
171 while( *pszPtr == ' ' )
172 pszPtr ++;
173 snprintf(jvmLib, sizeof(jvmLib), "%s/server/libjvm." SO_EXT, pszPtr);
174 jvmLibPtr = jvmLib;
175 }
176 }
177 }
178
179 CPLDebug("MDB", "Trying %s", jvmLibPtr);
180 jint (*pfnJNI_GetCreatedJavaVMs)(JavaVM **, jsize, jsize *);
181 pfnJNI_GetCreatedJavaVMs = (jint (*)(JavaVM **, jsize, jsize *))
182 CPLGetSymbol(jvmLibPtr, "JNI_GetCreatedJavaVMs");
183
184 if (pfnJNI_GetCreatedJavaVMs == nullptr)
185 {
186 CPLDebug("MDB", "Cannot find JNI_GetCreatedJavaVMs function");
187 return FALSE;
188 }
189 else
190 {
191 ret = pfnJNI_GetCreatedJavaVMs(vmBuf, 1, &nVMs);
192 }
193 #else
194 ret = JNI_GetCreatedJavaVMs(vmBuf, 1, &nVMs);
195 #endif
196
197 /* Are we already called from Java ? */
198 if (ret == JNI_OK && nVMs == 1)
199 {
200 jvm = vmBuf[0];
201 if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2) == JNI_OK)
202 {
203 bCalledFromJava = TRUE;
204 }
205 else
206 {
207 jvm = nullptr;
208 env = nullptr;
209 }
210 }
211 else
212 {
213 JavaVMInitArgs args;
214 JavaVMOption options[1];
215 args.version = JNI_VERSION_1_2;
216 const char* pszClassPath = CPLGetConfigOption("CLASSPATH", nullptr);
217 char* pszClassPathOption = nullptr;
218 if (pszClassPath)
219 {
220 args.nOptions = 1;
221 pszClassPathOption = CPLStrdup(CPLSPrintf("-Djava.class.path=%s", pszClassPath));
222 options[0].optionString = pszClassPathOption;
223 args.options = options;
224 }
225 else
226 args.nOptions = 0;
227 args.ignoreUnrecognized = JNI_FALSE;
228
229 #if JVM_LIB_DLOPEN
230 jint (*pfnJNI_CreateJavaVM)(JavaVM **, void **, void *);
231 pfnJNI_CreateJavaVM = (jint (*)(JavaVM **, void **, void *))
232 CPLGetSymbol(jvmLibPtr, "JNI_CreateJavaVM");
233
234 if (pfnJNI_CreateJavaVM == nullptr)
235 return FALSE;
236 else
237 ret = pfnJNI_CreateJavaVM(&jvm, (void **)&env, &args);
238 #else
239 ret = JNI_CreateJavaVM(&jvm, (void **)&env, &args);
240 #endif
241
242 CPLFree(pszClassPathOption);
243
244 if (ret != JNI_OK || jvm == nullptr || env == nullptr)
245 {
246 CPLError(CE_Failure, CPLE_AppDefined, "JNI_CreateJavaVM failed (%d)", ret);
247 return FALSE;
248 }
249
250 jvm_static = jvm;
251 }
252 }
253 else
254 {
255 jvm = jvm_static;
256 }
257
258 if( jvm == nullptr )
259 return FALSE;
260
261 if (jvm->GetEnv((void **)&env, JNI_VERSION_1_2) == JNI_EDETACHED )
262 {
263 jvm->AttachCurrentThread((void **)&env, nullptr);
264 }
265
266 if( env == nullptr )
267 return FALSE;
268
269 CHECK(byteArray_class, env->FindClass("[B"));
270 CHECK(file_class, env->FindClass("java/io/File"));
271 CHECK(file_constructor, env->GetMethodID(file_class, "<init>", "(Ljava/lang/String;)V"));
272 CHECK(database_class, env->FindClass("com/healthmarketscience/jackcess/Database"));
273
274 CHECK(database_open, env->GetStaticMethodID(database_class, "open", "(Ljava/io/File;Z)Lcom/healthmarketscience/jackcess/Database;"));
275 CHECK(database_close, env->GetMethodID(database_class, "close", "()V"));
276 CHECK(database_getTableNames, env->GetMethodID(database_class, "getTableNames", "()Ljava/util/Set;"));
277 CHECK(database_getTable, env->GetMethodID(database_class, "getTable", "(Ljava/lang/String;)Lcom/healthmarketscience/jackcess/Table;"));
278
279 CHECK(table_class, env->FindClass("com/healthmarketscience/jackcess/Table"));
280 CHECK(table_getColumns, env->GetMethodID(table_class, "getColumns", "()Ljava/util/List;"));
281 CHECK(table_iterator, env->GetMethodID(table_class, "iterator", "()Ljava/util/Iterator;"));
282 CHECK(table_getRowCount, env->GetMethodID(table_class, "getRowCount", "()I"));
283
284 CHECK(column_class, env->FindClass("com/healthmarketscience/jackcess/Column"));
285 CHECK(column_getName, env->GetMethodID(column_class, "getName", "()Ljava/lang/String;"));
286 CHECK(column_getType, env->GetMethodID(column_class, "getType", "()Lcom/healthmarketscience/jackcess/DataType;"));
287 CHECK(column_getLength, env->GetMethodID(column_class, "getLength", "()S"));
288 CHECK(column_isVariableLength, env->GetMethodID(column_class, "isVariableLength", "()Z"));
289
290 CHECK(datatype_class, env->FindClass("com/healthmarketscience/jackcess/DataType"));
291 CHECK(datatype_getValue, env->GetMethodID(datatype_class, "getValue", "()B"));
292
293 CHECK(list_class, env->FindClass("java/util/List"));
294 CHECK(list_iterator, env->GetMethodID(list_class, "iterator", "()Ljava/util/Iterator;"));
295
296 CHECK(set_class, env->FindClass("java/util/Set"));
297 CHECK(set_iterator, env->GetMethodID(set_class, "iterator", "()Ljava/util/Iterator;"));
298
299 CHECK(map_class, env->FindClass("java/util/Map"));
300 CHECK(map_get, env->GetMethodID(map_class, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"));
301
302 CHECK(iterator_class, env->FindClass("java/util/Iterator"));
303 CHECK(iterator_hasNext, env->GetMethodID(iterator_class, "hasNext", "()Z"));
304 CHECK(iterator_next, env->GetMethodID(iterator_class, "next", "()Ljava/lang/Object;"));
305
306 CHECK(object_class, env->FindClass("java/lang/Object"));
307 CHECK(object_toString, env->GetMethodID(object_class, "toString", "()Ljava/lang/String;"));
308 CHECK(object_getClass, env->GetMethodID(object_class, "getClass", "()Ljava/lang/Class;"));
309
310 CHECK(boolean_class, env->FindClass("java/lang/Boolean"));
311 CHECK(boolean_booleanValue, env->GetMethodID(boolean_class, "booleanValue", "()Z"));
312
313 CHECK(byte_class, env->FindClass("java/lang/Byte"));
314 CHECK(byte_byteValue, env->GetMethodID(byte_class, "byteValue", "()B"));
315
316 CHECK(short_class, env->FindClass("java/lang/Short"));
317 CHECK(short_shortValue, env->GetMethodID(short_class, "shortValue", "()S"));
318
319 CHECK(integer_class, env->FindClass("java/lang/Integer"));
320 CHECK(integer_intValue, env->GetMethodID(integer_class, "intValue", "()I"));
321
322 CHECK(float_class, env->FindClass("java/lang/Float"));
323 CHECK(float_floatValue, env->GetMethodID(float_class, "floatValue", "()F"));
324
325 CHECK(double_class, env->FindClass("java/lang/Double"));
326 CHECK(double_doubleValue, env->GetMethodID(integer_class, "doubleValue", "()D"));
327
328 return TRUE;
329 }
330
331 /************************************************************************/
332 /* ExceptionOccurred() */
333 /************************************************************************/
334
ExceptionOccurred()335 int OGRMDBJavaEnv::ExceptionOccurred()
336 {
337 jthrowable exc = env->ExceptionOccurred();
338 if (exc)
339 {
340 env->ExceptionDescribe();
341 env->ExceptionClear();
342 return TRUE;
343 }
344 return FALSE;
345 }
346
347 /************************************************************************/
348 /* OGRMDBDatabase() */
349 /************************************************************************/
350
OGRMDBDatabase()351 OGRMDBDatabase::OGRMDBDatabase()
352 {
353 }
354
355 /************************************************************************/
356 /* ~OGRMDBDatabase() */
357 /************************************************************************/
358
~OGRMDBDatabase()359 OGRMDBDatabase::~OGRMDBDatabase()
360 {
361 if (database)
362 {
363 CPLDebug("MDB", "Closing database");
364 env->env->CallVoidMethod(database, env->database_close);
365
366 env->env->DeleteGlobalRef(database);
367 }
368 }
369
370 /************************************************************************/
371 /* Open() */
372 /************************************************************************/
373
Open(OGRMDBJavaEnv * env,const char * pszName)374 OGRMDBDatabase* OGRMDBDatabase::Open(OGRMDBJavaEnv* env, const char* pszName)
375 {
376 jstring jstr = env->env->NewStringUTF(pszName);
377 jobject file = env->env->NewObject(env->file_class, env->file_constructor, jstr);
378 if (env->ExceptionOccurred()) return nullptr;
379 env->env->ReleaseStringUTFChars(jstr, nullptr);
380
381 jobject database = env->env->CallStaticObjectMethod(env->database_class, env->database_open, file, JNI_TRUE);
382
383 env->env->DeleteLocalRef(file);
384
385 if (env->ExceptionOccurred()) return nullptr;
386 if (database == nullptr)
387 return nullptr;
388
389 OGRMDBDatabase* poDB = new OGRMDBDatabase();
390 poDB->env = env;
391 poDB->database = env->env->NewGlobalRef(database);
392 env->env->DeleteLocalRef(database);
393 return poDB;
394 }
395
396 /************************************************************************/
397 /* FetchTableNames() */
398 /************************************************************************/
399
FetchTableNames()400 int OGRMDBDatabase::FetchTableNames()
401 {
402 if( !env->InitIfNeeded() )
403 return FALSE;
404
405 jobject table_set = env->env->CallObjectMethod(database, env->database_getTableNames);
406 if (env->ExceptionOccurred()) return FALSE;
407 jobject iterator = env->env->CallObjectMethod(table_set, env->set_iterator);
408 if (env->ExceptionOccurred()) return FALSE;
409
410 while( env->env->CallBooleanMethod(iterator, env->iterator_hasNext) )
411 {
412 if (env->ExceptionOccurred()) return FALSE;
413 jstring table_name_jstring = (jstring) env->env->CallObjectMethod(iterator, env->iterator_next);
414 if (env->ExceptionOccurred()) return FALSE;
415 jboolean is_copy;
416 const char* table_name_str = env->env->GetStringUTFChars(table_name_jstring, &is_copy);
417
418 apoTableNames.push_back(table_name_str);
419 //CPLDebug("MDB", "Table %s", table_name_str);
420
421 env->env->ReleaseStringUTFChars(table_name_jstring, table_name_str);
422 env->env->DeleteLocalRef(table_name_jstring);
423 }
424 env->env->DeleteLocalRef(iterator);
425 env->env->DeleteLocalRef(table_set);
426 return TRUE;
427 }
428
429 /************************************************************************/
430 /* GetTable() */
431 /************************************************************************/
432
GetTable(const char * pszTableName)433 OGRMDBTable* OGRMDBDatabase::GetTable(const char* pszTableName)
434 {
435 if( !env->InitIfNeeded() )
436 return nullptr;
437
438 jstring table_name_jstring = env->env->NewStringUTF(pszTableName);
439 jobject table = env->env->CallObjectMethod(database, env->database_getTable, table_name_jstring);
440 if (env->ExceptionOccurred()) return nullptr;
441 env->env->DeleteLocalRef(table_name_jstring);
442
443 if (!table)
444 return nullptr;
445
446 jobject global_table = env->env->NewGlobalRef(table);
447 env->env->DeleteLocalRef(table);
448 table = global_table;
449
450 OGRMDBTable* poTable = new OGRMDBTable(env, this, table, pszTableName);
451 if (!poTable->FetchColumns())
452 {
453 delete poTable;
454 return nullptr;
455 }
456 return poTable;
457 }
458
459 /************************************************************************/
460 /* OGRMDBTable() */
461 /************************************************************************/
462
OGRMDBTable(OGRMDBJavaEnv * envIn,OGRMDBDatabase * poDBIn,jobject tableIn,const char * pszTableName)463 OGRMDBTable::OGRMDBTable(OGRMDBJavaEnv* envIn, OGRMDBDatabase* poDBIn,
464 jobject tableIn, const char* pszTableName ) :
465 env(envIn), poDB(poDBIn), table(tableIn), osTableName( pszTableName )
466 {
467 }
468
469 /************************************************************************/
470 /* ~OGRMDBTable() */
471 /************************************************************************/
472
~OGRMDBTable()473 OGRMDBTable::~OGRMDBTable()
474 {
475 if (env && env->InitIfNeeded())
476 {
477 //CPLDebug("MDB", "Freeing table %s", osTableName.c_str());
478 int i;
479 for(i=0;i<(int)apoColumnNameObjects.size();i++)
480 env->env->DeleteGlobalRef(apoColumnNameObjects[i]);
481
482 env->env->DeleteGlobalRef(table_iterator_obj);
483 env->env->DeleteGlobalRef(row);
484 env->env->DeleteGlobalRef(table);
485 }
486 }
487
488 /************************************************************************/
489 /* FetchColumns() */
490 /************************************************************************/
491
FetchColumns()492 int OGRMDBTable::FetchColumns()
493 {
494 if( !env->InitIfNeeded() )
495 return FALSE;
496
497 jobject column_lists = env->env->CallObjectMethod(table, env->table_getColumns);
498 if (env->ExceptionOccurred()) return FALSE;
499
500 jobject iterator_cols = env->env->CallObjectMethod(column_lists, env->list_iterator);
501 if (env->ExceptionOccurred()) return FALSE;
502
503 while( env->env->CallBooleanMethod(iterator_cols, env->iterator_hasNext) )
504 {
505 if (env->ExceptionOccurred()) return FALSE;
506
507 jobject column = env->env->CallObjectMethod(iterator_cols, env->iterator_next);
508 if (env->ExceptionOccurred()) return FALSE;
509
510 jstring column_name_jstring = (jstring) env->env->CallObjectMethod(column, env->column_getName);
511 if (env->ExceptionOccurred()) return FALSE;
512 jboolean is_copy;
513 const char* column_name_str = env->env->GetStringUTFChars(column_name_jstring, &is_copy);
514 apoColumnNames.push_back(column_name_str);
515 env->env->ReleaseStringUTFChars(column_name_jstring, column_name_str);
516
517 apoColumnNameObjects.push_back((jstring) env->env->NewGlobalRef(column_name_jstring));
518 env->env->DeleteLocalRef(column_name_jstring);
519
520 jobject column_type = env->env->CallObjectMethod(column, env->column_getType);
521 if (env->ExceptionOccurred()) return FALSE;
522 int type = env->env->CallByteMethod(column_type, env->datatype_getValue);
523 if (env->ExceptionOccurred()) return FALSE;
524 apoColumnTypes.push_back(type);
525
526 int isvariablelength = env->env->CallBooleanMethod(column, env->column_isVariableLength);
527 if (env->ExceptionOccurred()) return FALSE;
528 if (!isvariablelength)
529 {
530 int length = env->env->CallShortMethod(column, env->column_getLength);
531 if (env->ExceptionOccurred()) return FALSE;
532 apoColumnLengths.push_back(length);
533 }
534 else
535 apoColumnLengths.push_back(0);
536
537 //CPLDebug("MDB", "Column %s, type = %d", apoColumnNames.back().c_str(), type);
538
539 env->env->DeleteLocalRef(column_type);
540
541 env->env->DeleteLocalRef(column);
542 }
543 env->env->DeleteLocalRef(iterator_cols);
544 env->env->DeleteLocalRef(column_lists);
545
546 return TRUE;
547 }
548
549 /************************************************************************/
550 /* ResetReading() */
551 /************************************************************************/
552
ResetReading()553 void OGRMDBTable::ResetReading()
554 {
555 if( !env->InitIfNeeded() )
556 return;
557
558 env->env->DeleteGlobalRef(table_iterator_obj);
559 table_iterator_obj = nullptr;
560 env->env->DeleteGlobalRef(row);
561 row = nullptr;
562 }
563
564 /************************************************************************/
565 /* GetNextRow() */
566 /************************************************************************/
567
GetNextRow()568 int OGRMDBTable::GetNextRow()
569 {
570 if( !env->InitIfNeeded() )
571 return FALSE;
572
573 if (table_iterator_obj == nullptr)
574 {
575 table_iterator_obj = env->env->CallObjectMethod(table, env->table_iterator);
576 if (env->ExceptionOccurred()) return FALSE;
577 if (table_iterator_obj)
578 {
579 jobject global_table_iterator_obj = env->env->NewGlobalRef(table_iterator_obj);
580 env->env->DeleteLocalRef(table_iterator_obj);
581 table_iterator_obj = global_table_iterator_obj;
582 }
583 }
584 if (table_iterator_obj == nullptr)
585 return FALSE;
586
587 if (!env->env->CallBooleanMethod(table_iterator_obj, env->iterator_hasNext))
588 return FALSE;
589 if (env->ExceptionOccurred()) return FALSE;
590
591 if (row)
592 {
593 env->env->DeleteGlobalRef(row);
594 row = nullptr;
595 }
596
597 row = env->env->CallObjectMethod(table_iterator_obj, env->iterator_next);
598 if (env->ExceptionOccurred()) return FALSE;
599 if (row == nullptr)
600 return FALSE;
601
602 jobject global_row = env->env->NewGlobalRef(row);
603 env->env->DeleteLocalRef(row);
604 row = global_row;
605
606 return TRUE;
607 }
608
609 /************************************************************************/
610 /* GetColumnVal() */
611 /************************************************************************/
612
GetColumnVal(int iCol)613 jobject OGRMDBTable::GetColumnVal(int iCol)
614 {
615 if (row == nullptr)
616 return nullptr;
617
618 jobject val = env->env->CallObjectMethod(row, env->map_get, apoColumnNameObjects[iCol]);
619 if (env->ExceptionOccurred()) return nullptr;
620 return val;
621 }
622
623 /************************************************************************/
624 /* GetColumnAsString() */
625 /************************************************************************/
626
GetColumnAsString(int iCol)627 char* OGRMDBTable::GetColumnAsString(int iCol)
628 {
629 jobject val = GetColumnVal(iCol);
630 if (!val) return nullptr;
631
632 jstring val_jstring = (jstring) env->env->CallObjectMethod(val, env->object_toString);
633 if (env->ExceptionOccurred()) return nullptr;
634 jboolean is_copy;
635 const char* val_str = env->env->GetStringUTFChars(val_jstring, &is_copy);
636 char* dup_str = (val_str) ? CPLStrdup(val_str) : nullptr;
637 env->env->ReleaseStringUTFChars(val_jstring, val_str);
638 env->env->DeleteLocalRef(val_jstring);
639
640 env->env->DeleteLocalRef(val);
641
642 return dup_str;
643 }
644
645 /************************************************************************/
646 /* GetColumnAsInt() */
647 /************************************************************************/
648
GetColumnAsInt(int iCol)649 int OGRMDBTable::GetColumnAsInt(int iCol)
650 {
651 jobject val = GetColumnVal(iCol);
652 if (!val) return 0;
653
654 int int_val = 0;
655 if (apoColumnTypes[iCol] == MDB_Boolean)
656 int_val = env->env->CallBooleanMethod(val, env->boolean_booleanValue);
657 else if (apoColumnTypes[iCol] == MDB_Byte)
658 int_val = env->env->CallByteMethod(val, env->byte_byteValue);
659 else if (apoColumnTypes[iCol] == MDB_Short)
660 int_val = env->env->CallShortMethod(val, env->short_shortValue);
661 else if (apoColumnTypes[iCol] == MDB_Int)
662 int_val = env->env->CallIntMethod(val, env->integer_intValue);
663 if (env->ExceptionOccurred()) return 0;
664
665 env->env->DeleteLocalRef(val);
666
667 return int_val;
668 }
669
670 /************************************************************************/
671 /* GetColumnAsDouble() */
672 /************************************************************************/
673
GetColumnAsDouble(int iCol)674 double OGRMDBTable::GetColumnAsDouble(int iCol)
675 {
676 jobject val = GetColumnVal(iCol);
677 if (!val) return 0;
678
679 double double_val = 0;
680 if (apoColumnTypes[iCol] == MDB_Double)
681 double_val = env->env->CallDoubleMethod(val, env->double_doubleValue);
682 else if (apoColumnTypes[iCol] == MDB_Float)
683 double_val = env->env->CallFloatMethod(val, env->float_floatValue);
684 if (env->ExceptionOccurred()) return 0;
685
686 env->env->DeleteLocalRef(val);
687
688 return double_val;
689 }
690
691 /************************************************************************/
692 /* GetColumnAsBinary() */
693 /************************************************************************/
694
GetColumnAsBinary(int iCol,int * pnBytes)695 GByte* OGRMDBTable::GetColumnAsBinary(int iCol, int* pnBytes)
696 {
697 *pnBytes = 0;
698
699 jobject val = GetColumnVal(iCol);
700 if (!val) return nullptr;
701
702 if (!env->env->IsInstanceOf(val, env->byteArray_class))
703 return nullptr;
704
705 jbyteArray byteArray = (jbyteArray) val;
706 *pnBytes = env->env->GetArrayLength(byteArray);
707 if (env->ExceptionOccurred()) return nullptr;
708 jboolean is_copy;
709 jbyte* elts = env->env->GetByteArrayElements(byteArray, &is_copy);
710 if (env->ExceptionOccurred()) return nullptr;
711
712 GByte* pData = (GByte*)CPLMalloc(*pnBytes);
713 memcpy(pData, elts, *pnBytes);
714
715 env->env->ReleaseByteArrayElements(byteArray, elts, JNI_ABORT);
716
717 env->env->DeleteLocalRef(val);
718
719 return pData;
720 }
721
722 /************************************************************************/
723 /* DumpTable() */
724 /************************************************************************/
725
DumpTable()726 void OGRMDBTable::DumpTable()
727 {
728 ResetReading();
729 int iRow = 0;
730 int nCols = static_cast<int>(apoColumnNames.size());
731 while(GetNextRow())
732 {
733 printf("Row = %d\n", iRow ++);/*ok*/
734 for(int i=0;i<nCols;i++)
735 {
736 printf("%s = ", apoColumnNames[i].c_str());/*ok*/
737 if (apoColumnTypes[i] == MDB_Float ||
738 apoColumnTypes[i] == MDB_Double)
739 {
740 printf("%.15f\n", GetColumnAsDouble(i));/*ok*/
741 }
742 else if (apoColumnTypes[i] == MDB_Boolean ||
743 apoColumnTypes[i] == MDB_Byte ||
744 apoColumnTypes[i] == MDB_Short ||
745 apoColumnTypes[i] == MDB_Int)
746 {
747 printf("%d\n", GetColumnAsInt(i));/*ok*/
748 }
749 else if (apoColumnTypes[i] == MDB_Binary ||
750 apoColumnTypes[i] == MDB_OLE)
751 {
752 int nBytes;
753 GByte* pData = GetColumnAsBinary(i, &nBytes);
754 printf("(%d bytes)\n", nBytes);/*ok*/
755 CPLFree(pData);
756 }
757 else
758 {
759 char* val = GetColumnAsString(i);
760 printf("'%s'\n", val);/*ok*/
761 CPLFree(val);
762 }
763 }
764 }
765 }
766
767 /************************************************************************/
768 /* GetColumnIndex() */
769 /************************************************************************/
770
GetColumnIndex(const char * pszColName,int bEmitErrorIfNotFound)771 int OGRMDBTable::GetColumnIndex(const char* pszColName, int bEmitErrorIfNotFound)
772 {
773 int nCols = static_cast<int>(apoColumnNames.size());
774 CPLString osColName(pszColName);
775 for(int i=0;i<nCols;i++)
776 {
777 if (apoColumnNames[i] == osColName)
778 return i;
779 }
780 if (bEmitErrorIfNotFound)
781 CPLError(CE_Failure, CPLE_AppDefined, "Cannot find column %s", pszColName);
782 return -1;
783 }
784
785 /************************************************************************/
786 /* GetRowCount() */
787 /************************************************************************/
788
GetRowCount()789 int OGRMDBTable::GetRowCount()
790 {
791 if( !env->InitIfNeeded() )
792 return 0;
793
794 int nRowCount = env->env->CallIntMethod(table, env->table_getRowCount);
795 if (env->ExceptionOccurred()) return 0;
796 return nRowCount;
797 }
798