This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch branch-3.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-3.1 by this push:
new a6e0ac5ad5a branch-3.1:[fix](jni)add ExceptionCheck for safe jni call.
#51913 (#53343)
a6e0ac5ad5a is described below
commit a6e0ac5ad5a182004145148cfa6059861bd80a46
Author: daidai <[email protected]>
AuthorDate: Thu Jul 17 11:28:39 2025 +0800
branch-3.1:[fix](jni)add ExceptionCheck for safe jni call. #51913 (#53343)
cherry picked from #51913
---
be/src/util/jni-util.cpp | 65 ++++++++++++++++------
be/src/util/jni-util.h | 6 +-
.../aggregate_function_java_udaf.h | 12 ++--
.../format/table/trino_connector_jni_reader.cpp | 3 +
be/src/vec/exec/jni_connector.cpp | 46 +++++++++++----
be/src/vec/exec/jni_connector.h | 24 ++++----
be/src/vec/exec/vjdbc_connector.cpp | 48 ++++++++++------
be/src/vec/exec/vjdbc_connector.h | 6 +-
.../exprs/table_function/udf_table_function.cpp | 12 ++--
.../vec/exprs/table_function/udf_table_function.h | 2 +
be/src/vec/functions/function_java_udf.cpp | 14 +++--
be/src/vec/functions/function_java_udf.h | 2 +
regression-test/pipeline/external/conf/be.conf | 4 +-
regression-test/pipeline/p0/conf/be.conf | 4 +-
14 files changed, 170 insertions(+), 78 deletions(-)
diff --git a/be/src/util/jni-util.cpp b/be/src/util/jni-util.cpp
index d0b24415eb6..47675ba1714 100644
--- a/be/src/util/jni-util.cpp
+++ b/be/src/util/jni-util.cpp
@@ -315,66 +315,83 @@ Status JniUtil::GetJniExceptionMsg(JNIEnv* env, bool
log_stack, const string& pr
return Status::RuntimeError("{}{}", prefix, msg_str_guard.get());
}
-jobject JniUtil::convert_to_java_map(JNIEnv* env, const std::map<std::string,
std::string>& map) {
- //TODO: ADD EXCEPTION CHECK.
+Status JniUtil::convert_to_java_map(JNIEnv* env, const std::map<std::string,
std::string>& map,
+ jobject* hashmap_object) {
jclass hashmap_class = env->FindClass("java/util/HashMap");
+ RETURN_ERROR_IF_EXC(env);
jmethodID hashmap_constructor = env->GetMethodID(hashmap_class, "<init>",
"(I)V");
- jobject hashmap_object = env->NewObject(hashmap_class,
hashmap_constructor, map.size());
+ RETURN_ERROR_IF_EXC(env);
+ jobject hashmap_local_object = env->NewObject(hashmap_class,
hashmap_constructor, map.size());
+ RETURN_ERROR_IF_EXC(env);
jmethodID hashmap_put = env->GetMethodID(
hashmap_class, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ RETURN_ERROR_IF_EXC(env);
for (const auto& it : map) {
jstring key = env->NewStringUTF(it.first.c_str());
jstring value = env->NewStringUTF(it.second.c_str());
- env->CallObjectMethod(hashmap_object, hashmap_put, key, value);
+ env->CallObjectMethod(hashmap_local_object, hashmap_put, key, value);
+ RETURN_ERROR_IF_EXC(env);
env->DeleteLocalRef(key);
env->DeleteLocalRef(value);
}
env->DeleteLocalRef(hashmap_class);
- return hashmap_object;
+ RETURN_IF_ERROR(LocalToGlobalRef(env, hashmap_local_object,
hashmap_object));
+ return Status::OK();
}
-std::map<std::string, std::string> JniUtil::convert_to_cpp_map(JNIEnv* env,
jobject map) {
- std::map<std::string, std::string> resultMap;
-
+Status JniUtil::convert_to_cpp_map(JNIEnv* env, jobject map,
+ std::map<std::string, std::string>*
resultMap) {
// Get the class and method ID of the java.util.Map interface
jclass mapClass = env->FindClass("java/util/Map");
+ RETURN_ERROR_IF_EXC(env);
jmethodID entrySetMethod = env->GetMethodID(mapClass, "entrySet",
"()Ljava/util/Set;");
// Get the class and method ID of the java.util.Set interface
jclass setClass = env->FindClass("java/util/Set");
+ RETURN_ERROR_IF_EXC(env);
jmethodID iteratorSetMethod = env->GetMethodID(setClass, "iterator",
"()Ljava/util/Iterator;");
// Get the class and method ID of the java.util.Iterator interface
jclass iteratorClass = env->FindClass("java/util/Iterator");
+ RETURN_ERROR_IF_EXC(env);
jmethodID hasNextMethod = env->GetMethodID(iteratorClass, "hasNext",
"()Z");
jmethodID nextMethod = env->GetMethodID(iteratorClass, "next",
"()Ljava/lang/Object;");
// Get the class and method ID of the java.util.Map.Entry interface
jclass entryClass = env->FindClass("java/util/Map$Entry");
+ RETURN_ERROR_IF_EXC(env);
jmethodID getKeyMethod = env->GetMethodID(entryClass, "getKey",
"()Ljava/lang/Object;");
jmethodID getValueMethod = env->GetMethodID(entryClass, "getValue",
"()Ljava/lang/Object;");
// Call the entrySet method to get the set of key-value pairs
jobject entrySet = env->CallObjectMethod(map, entrySetMethod);
+ RETURN_ERROR_IF_EXC(env);
// Call the iterator method on the set to iterate over the key-value pairs
jobject iteratorSet = env->CallObjectMethod(entrySet, iteratorSetMethod);
+ RETURN_ERROR_IF_EXC(env);
// Iterate over the key-value pairs
while (env->CallBooleanMethod(iteratorSet, hasNextMethod)) {
+ RETURN_ERROR_IF_EXC(env);
+
// Get the current entry
jobject entry = env->CallObjectMethod(iteratorSet, nextMethod);
+ RETURN_ERROR_IF_EXC(env);
// Get the key and value from the entry
jobject javaKey = env->CallObjectMethod(entry, getKeyMethod);
+ RETURN_ERROR_IF_EXC(env);
+
jobject javaValue = env->CallObjectMethod(entry, getValueMethod);
+ RETURN_ERROR_IF_EXC(env);
// Convert the key and value to C++ strings
const char* key =
env->GetStringUTFChars(static_cast<jstring>(javaKey), nullptr);
const char* value =
env->GetStringUTFChars(static_cast<jstring>(javaValue), nullptr);
// Store the key-value pair in the map
- resultMap[key] = value;
+ (*resultMap)[key] = value;
// Release the string references
env->ReleaseStringUTFChars(static_cast<jstring>(javaKey), key);
@@ -394,7 +411,7 @@ std::map<std::string, std::string>
JniUtil::convert_to_cpp_map(JNIEnv* env, jobj
env->DeleteLocalRef(iteratorClass);
env->DeleteLocalRef(entryClass);
- return resultMap;
+ return Status::OK();
}
Status JniUtil::GetGlobalClassRef(JNIEnv* env, const char* class_str, jclass*
class_ref) {
@@ -443,13 +460,12 @@ Status JniUtil::init_jni_scanner_loader(JNIEnv* env) {
env->GetMethodID(jni_scanner_loader_cls, "loadAllScannerJars",
"()V");
RETURN_ERROR_IF_EXC(env);
- jni_scanner_loader_obj_ =
+ jobject jni_scanner_loader_local_obj =
env->NewObject(jni_scanner_loader_cls,
jni_scanner_loader_constructor);
+ jni_scanner_loader_obj_ = env->NewGlobalRef(jni_scanner_loader_local_obj);
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteLocalRef(jni_scanner_loader_local_obj);
RETURN_ERROR_IF_EXC(env);
- if (jni_scanner_loader_obj_ == NULL) {
- if (env->ExceptionOccurred()) env->ExceptionDescribe();
- return Status::InternalError("Failed to create ScannerLoader object.");
- }
env->CallVoidMethod(jni_scanner_loader_obj_, load_jni_scanner);
RETURN_ERROR_IF_EXC(env);
@@ -468,8 +484,12 @@ Status JniUtil::init_jni_scanner_loader(JNIEnv* env) {
Status JniUtil::clean_udf_class_load_cache(const std::string&
function_signature) {
JNIEnv* env = nullptr;
RETURN_IF_ERROR(JniUtil::GetJNIEnv(&env));
+ jstring function_signature_jstr =
env->NewStringUTF(function_signature.c_str());
+ RETURN_ERROR_IF_EXC(env);
env->CallVoidMethod(jni_scanner_loader_obj_, _clean_udf_cache_method_id,
- env->NewStringUTF(function_signature.c_str()));
+ function_signature_jstr);
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteLocalRef(function_signature_jstr);
RETURN_ERROR_IF_EXC(env);
return Status::OK();
}
@@ -477,11 +497,20 @@ Status JniUtil::clean_udf_class_load_cache(const
std::string& function_signature
Status JniUtil::get_jni_scanner_class(JNIEnv* env, const char* classname,
jclass* jni_scanner_class) {
// Get JNI scanner class by class name;
- jobject loaded_class_obj = env->CallObjectMethod(
- jni_scanner_loader_obj_, jni_scanner_loader_method_,
env->NewStringUTF(classname));
+ jstring class_name_str = env->NewStringUTF(classname);
RETURN_ERROR_IF_EXC(env);
+
+ jobject loaded_class_obj = env->CallObjectMethod(jni_scanner_loader_obj_,
+
jni_scanner_loader_method_, class_name_str);
+ RETURN_ERROR_IF_EXC(env);
+
*jni_scanner_class =
reinterpret_cast<jclass>(env->NewGlobalRef(loaded_class_obj));
RETURN_ERROR_IF_EXC(env);
+
+ env->DeleteLocalRef(loaded_class_obj);
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteLocalRef(class_name_str);
+ RETURN_ERROR_IF_EXC(env);
return Status::OK();
}
diff --git a/be/src/util/jni-util.h b/be/src/util/jni-util.h
index df332951afe..1a2e751b69e 100644
--- a/be/src/util/jni-util.h
+++ b/be/src/util/jni-util.h
@@ -101,8 +101,10 @@ public:
return INITIAL_RESERVED_BUFFER_SIZE << n;
}
static Status get_jni_scanner_class(JNIEnv* env, const char* classname,
jclass* loaded_class);
- static jobject convert_to_java_map(JNIEnv* env, const
std::map<std::string, std::string>& map);
- static std::map<std::string, std::string> convert_to_cpp_map(JNIEnv* env,
jobject map);
+ static Status convert_to_java_map(JNIEnv* env, const std::map<std::string,
std::string>& map,
+ jobject* hashmap_object);
+ static Status convert_to_cpp_map(JNIEnv* env, jobject map,
+ std::map<std::string, std::string>*
resultMap);
static size_t get_max_jni_heap_memory_size();
static Status clean_udf_class_load_cache(const std::string&
function_signature);
diff --git a/be/src/vec/aggregate_functions/aggregate_function_java_udaf.h
b/be/src/vec/aggregate_functions/aggregate_function_java_udaf.h
index 366b242927a..a215a3a7f8c 100644
--- a/be/src/vec/aggregate_functions/aggregate_function_java_udaf.h
+++ b/be/src/vec/aggregate_functions/aggregate_function_java_udaf.h
@@ -132,11 +132,13 @@ public:
{"meta_address", std::to_string((long)input_table.get())},
{"required_fields", input_table_schema.first},
{"columns_types", input_table_schema.second}};
- jobject input_map = JniUtil::convert_to_java_map(env, input_params);
+ jobject input_map = nullptr;
+ RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, input_params,
&input_map));
// invoke add batch
env->CallObjectMethod(executor_obj, executor_add_batch_id,
is_single_place, row_num_start,
row_num_end, places_address, place_offset,
input_map);
- env->DeleteLocalRef(input_map);
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteGlobalRef(input_map);
return JniUtil::GetJniExceptionMsg(env);
}
@@ -200,10 +202,12 @@ public:
std::map<String, String> output_params = {{"is_nullable",
output_nullable},
{"required_fields",
output_table_schema.first},
{"columns_types",
output_table_schema.second}};
- jobject output_map = JniUtil::convert_to_java_map(env, output_params);
+ jobject output_map = nullptr;
+ RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, output_params,
&output_map));
long output_address =
env->CallLongMethod(executor_obj, executor_get_value_id,
place, output_map);
- env->DeleteLocalRef(output_map);
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteGlobalRef(output_map);
RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
return JniConnector::fill_block(&output_block, {0}, output_address);
}
diff --git a/be/src/vec/exec/format/table/trino_connector_jni_reader.cpp
b/be/src/vec/exec/format/table/trino_connector_jni_reader.cpp
index 8c7f5e5440c..f4ebd432f67 100644
--- a/be/src/vec/exec/format/table/trino_connector_jni_reader.cpp
+++ b/be/src/vec/exec/format/table/trino_connector_jni_reader.cpp
@@ -107,9 +107,12 @@ Status TrinoConnectorJniReader::_set_spi_plugins_dir() {
// call: setPluginsDir(String pluginsDir)
jstring trino_connector_plugin_path =
env->NewStringUTF(doris::config::trino_connector_plugin_dir.c_str());
+ RETURN_ERROR_IF_EXC(env);
env->CallStaticVoidMethod(plugin_loader_cls, set_plugins_dir_method,
trino_connector_plugin_path);
RETURN_ERROR_IF_EXC(env);
+ env->DeleteLocalRef(trino_connector_plugin_path);
+ RETURN_ERROR_IF_EXC(env);
return Status::OK();
}
diff --git a/be/src/vec/exec/jni_connector.cpp
b/be/src/vec/exec/jni_connector.cpp
index 47c84b72c6e..3030c2bde57 100644
--- a/be/src/vec/exec/jni_connector.cpp
+++ b/be/src/vec/exec/jni_connector.cpp
@@ -149,27 +149,36 @@ Status JniConnector::get_next_block(Block* block, size_t*
read_rows, bool* eof)
Status JniConnector::get_table_schema(std::string& table_schema_str) {
JNIEnv* env = nullptr;
RETURN_IF_ERROR(JniUtil::GetJNIEnv(&env));
- // Call org.apache.doris.jni.JniScanner#getTableSchema
- // return the TableSchema information
+
jstring jstr = (jstring)env->CallObjectMethod(_jni_scanner_obj,
_jni_scanner_get_table_schema);
RETURN_ERROR_IF_EXC(env);
- table_schema_str = env->GetStringUTFChars(jstr, nullptr);
+
+ const char* cstr = env->GetStringUTFChars(jstr, nullptr);
RETURN_ERROR_IF_EXC(env);
+
+ if (cstr == nullptr) {
+ return Status::RuntimeError("GetStringUTFChars returned null");
+ }
+
+ table_schema_str = std::string(cstr); // copy to std::string
+ env->ReleaseStringUTFChars(jstr, cstr);
+ env->DeleteLocalRef(jstr);
return Status::OK();
}
-std::map<std::string, std::string> JniConnector::get_statistics(JNIEnv* env) {
+Status JniConnector::get_statistics(JNIEnv* env, std::map<std::string,
std::string>* result) {
+ result->clear();
jobject metrics = env->CallObjectMethod(_jni_scanner_obj,
_jni_scanner_get_statistics);
jthrowable exc = (env)->ExceptionOccurred();
if (exc != nullptr) {
LOG(WARNING) << "get_statistics has error: "
<< JniUtil::GetJniExceptionMsg(env).to_string();
env->DeleteLocalRef(metrics);
- return std::map<std::string, std::string> {};
+ return Status::OK();
}
- std::map<std::string, std::string> result =
JniUtil::convert_to_cpp_map(env, metrics);
+ RETURN_IF_ERROR(JniUtil::convert_to_cpp_map(env, metrics, result));
env->DeleteLocalRef(metrics);
- return result;
+ return Status::OK();
}
Status JniConnector::close() {
@@ -180,12 +189,15 @@ Status JniConnector::close() {
COUNTER_UPDATE(_open_scanner_time, _jni_scanner_open_watcher);
COUNTER_UPDATE(_fill_block_time, _fill_block_watcher);
+ RETURN_ERROR_IF_EXC(env);
int64_t _append = (int64_t)env->CallLongMethod(_jni_scanner_obj,
_jni_scanner_get_append_data_time);
+ RETURN_ERROR_IF_EXC(env);
COUNTER_UPDATE(_java_append_data_time, _append);
int64_t _create = (int64_t)env->CallLongMethod(
_jni_scanner_obj,
_jni_scanner_get_create_vector_table_time);
+ RETURN_ERROR_IF_EXC(env);
COUNTER_UPDATE(_java_create_vector_table_time, _create);
COUNTER_UPDATE(_java_scan_time, _java_scan_watcher - _append -
_create);
@@ -197,8 +209,11 @@ Status JniConnector::close() {
// _fill_block may be failed and returned, we should release table
in close.
// org.apache.doris.common.jni.JniScanner#releaseTable is
idempotent
env->CallVoidMethod(_jni_scanner_obj, _jni_scanner_release_table);
+ RETURN_ERROR_IF_EXC(env);
env->CallVoidMethod(_jni_scanner_obj, _jni_scanner_close);
+ RETURN_ERROR_IF_EXC(env);
env->DeleteGlobalRef(_jni_scanner_obj);
+ RETURN_ERROR_IF_EXC(env);
}
if (_jni_scanner_cls != nullptr) {
// _jni_scanner_cls may be null if init connector failed
@@ -218,7 +233,7 @@ Status JniConnector::close() {
Status JniConnector::_init_jni_scanner(JNIEnv* env, int batch_size) {
RETURN_IF_ERROR(
JniUtil::get_jni_scanner_class(env, _connector_class.c_str(),
&_jni_scanner_cls));
- if (_jni_scanner_cls == nullptr) {
+ if (_jni_scanner_cls == nullptr) [[unlikely]] {
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
}
@@ -231,14 +246,15 @@ Status JniConnector::_init_jni_scanner(JNIEnv* env, int
batch_size) {
RETURN_ERROR_IF_EXC(env);
// prepare constructor parameters
- jobject hashmap_object = JniUtil::convert_to_java_map(env,
_scanner_params);
+ jobject hashmap_object;
+ RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, _scanner_params,
&hashmap_object));
jobject jni_scanner_obj =
env->NewObject(_jni_scanner_cls, scanner_constructor, batch_size,
hashmap_object);
RETURN_ERROR_IF_EXC(env);
// prepare constructor parameters
- env->DeleteLocalRef(hashmap_object);
+ env->DeleteGlobalRef(hashmap_object);
RETURN_ERROR_IF_EXC(env);
_jni_scanner_open = env->GetMethodID(_jni_scanner_cls, "open", "()V");
@@ -259,6 +275,7 @@ Status JniConnector::_init_jni_scanner(JNIEnv* env, int
batch_size) {
_jni_scanner_release_table = env->GetMethodID(_jni_scanner_cls,
"releaseTable", "()V");
_jni_scanner_get_statistics =
env->GetMethodID(_jni_scanner_cls, "getStatistics",
"()Ljava/util/Map;");
+ RETURN_ERROR_IF_EXC(env);
RETURN_IF_ERROR(JniUtil::LocalToGlobalRef(env, jni_scanner_obj,
&_jni_scanner_obj));
env->DeleteLocalRef(jni_scanner_obj);
RETURN_ERROR_IF_EXC(env);
@@ -781,7 +798,14 @@ void JniConnector::_collect_profile_before_close() {
return;
}
// update scanner metrics
- for (const auto& metric : get_statistics(env)) {
+ std::map<std::string, std::string> statistics_result;
+ st = get_statistics(env, &statistics_result);
+ if (!st) {
+ LOG(WARNING) << "failed to get_statistics when collect profile: "
<< st;
+ return;
+ }
+
+ for (const auto& metric : statistics_result) {
std::vector<std::string> type_and_name = split(metric.first, ":");
if (type_and_name.size() != 2) {
LOG(WARNING) << "Name of JNI Scanner metric should be pattern
like "
diff --git a/be/src/vec/exec/jni_connector.h b/be/src/vec/exec/jni_connector.h
index 89168b5a551..db35d14bd26 100644
--- a/be/src/vec/exec/jni_connector.h
+++ b/be/src/vec/exec/jni_connector.h
@@ -242,7 +242,7 @@ public:
/**
* Get performance metrics from java scanner
*/
- std::map<std::string, std::string> get_statistics(JNIEnv* env);
+ Status get_statistics(JNIEnv* env, std::map<std::string, std::string>*
result);
/**
* Call java side function JniScanner.getTableSchema.
@@ -305,17 +305,17 @@ private:
bool _closed = false;
bool _scanner_opened = false;
- jclass _jni_scanner_cls;
- jobject _jni_scanner_obj;
- jmethodID _jni_scanner_open;
- jmethodID _jni_scanner_get_append_data_time;
- jmethodID _jni_scanner_get_create_vector_table_time;
- jmethodID _jni_scanner_get_next_batch;
- jmethodID _jni_scanner_get_table_schema;
- jmethodID _jni_scanner_close;
- jmethodID _jni_scanner_release_column;
- jmethodID _jni_scanner_release_table;
- jmethodID _jni_scanner_get_statistics;
+ jclass _jni_scanner_cls = nullptr;
+ jobject _jni_scanner_obj = nullptr;
+ jmethodID _jni_scanner_open = nullptr;
+ jmethodID _jni_scanner_get_append_data_time = nullptr;
+ jmethodID _jni_scanner_get_create_vector_table_time = nullptr;
+ jmethodID _jni_scanner_get_next_batch = nullptr;
+ jmethodID _jni_scanner_get_table_schema = nullptr;
+ jmethodID _jni_scanner_close = nullptr;
+ jmethodID _jni_scanner_release_column = nullptr;
+ jmethodID _jni_scanner_release_table = nullptr;
+ jmethodID _jni_scanner_get_statistics = nullptr;
TableMetaAddress _table_meta;
diff --git a/be/src/vec/exec/vjdbc_connector.cpp
b/be/src/vec/exec/vjdbc_connector.cpp
index f3f4b4d8a1c..a8d8d6fd210 100644
--- a/be/src/vec/exec/vjdbc_connector.cpp
+++ b/be/src/vec/exec/vjdbc_connector.cpp
@@ -77,10 +77,13 @@ Status JdbcConnector::close(Status /*unused*/) {
JNIEnv* env = nullptr;
RETURN_IF_ERROR(JniUtil::GetJNIEnv(&env));
env->CallNonvirtualVoidMethod(_executor_obj, _executor_clazz,
_executor_close_id);
+ RETURN_ERROR_IF_EXC(env);
env->DeleteGlobalRef(_executor_factory_clazz);
+ RETURN_ERROR_IF_EXC(env);
env->DeleteGlobalRef(_executor_clazz);
RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
env->DeleteGlobalRef(_executor_obj);
+ RETURN_ERROR_IF_EXC(env);
return Status::OK();
}
@@ -100,7 +103,8 @@ Status JdbcConnector::open(RuntimeState* state, bool read) {
GetStaticMethodID(_executor_factory_clazz, "getExecutorClass",
"(Lorg/apache/doris/thrift/TOdbcTableType;)Ljava/lang/String;"));
- jobject jtable_type = _get_java_table_type(env, _conn_param.table_type);
+ jobject jtable_type = nullptr;
+ RETURN_IF_ERROR(_get_java_table_type(env, _conn_param.table_type,
&jtable_type));
JNI_CALL_METHOD_CHECK_EXCEPTION_DELETE_REF(
jobject, executor_name, env,
@@ -110,8 +114,11 @@ Status JdbcConnector::open(RuntimeState* state, bool read)
{
const char* executor_name_str =
env->GetStringUTFChars((jstring)executor_name, nullptr);
RETURN_IF_ERROR(JniUtil::get_jni_scanner_class(env, executor_name_str,
&_executor_clazz));
- env->DeleteLocalRef(jtable_type);
+
+ env->DeleteGlobalRef(jtable_type);
+ RETURN_ERROR_IF_EXC(env);
env->ReleaseStringUTFChars((jstring)executor_name, executor_name_str);
+ RETURN_ERROR_IF_EXC(env);
#undef GET_BASIC_JAVA_CLAZZ
RETURN_IF_ERROR(_register_func_id(env));
@@ -236,6 +243,7 @@ Status JdbcConnector::get_next(bool* eos, Block* block, int
batch_size) {
SCOPED_RAW_TIMER(&_jdbc_statistic._has_next_timer); // Timer for
hasNext check
has_next = env->CallNonvirtualBooleanMethod(_executor_obj,
_executor_clazz,
_executor_has_next_id);
+ RETURN_ERROR_IF_EXC(env);
} // _has_next_timer stops here
if (has_next != JNI_TRUE) {
@@ -248,10 +256,10 @@ Status JdbcConnector::get_next(bool* eos, Block* block,
int batch_size) {
auto column_size = _tuple_desc->slots().size();
auto slots = _tuple_desc->slots();
- jobject map;
+ jobject map = nullptr;
{
SCOPED_RAW_TIMER(&_jdbc_statistic._prepare_params_timer); // Timer for
preparing params
- map = _get_reader_params(block, env, column_size);
+ RETURN_IF_ERROR(_get_reader_params(block, env, column_size, &map));
} // _prepare_params_timer stops here
long address = 0;
@@ -264,7 +272,8 @@ Status JdbcConnector::get_next(bool* eos, Block* block, int
batch_size) {
} // _get_block_address_timer stops here
RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
- env->DeleteLocalRef(map);
+ env->DeleteGlobalRef(map);
+ RETURN_ERROR_IF_EXC(env);
std::vector<size_t> all_columns;
for (size_t i = 0; i < column_size; ++i) {
@@ -315,10 +324,12 @@ Status JdbcConnector::exec_stmt_write(Block* block, const
VExprContextSPtrs& out
std::map<String, String> write_params = {{"meta_address",
std::to_string(meta_address)},
{"required_fields",
table_schema.first},
{"columns_types",
table_schema.second}};
- jobject hashmap_object = JniUtil::convert_to_java_map(env, write_params);
+ jobject hashmap_object = nullptr;
+ RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, write_params,
&hashmap_object));
+
env->CallNonvirtualIntMethod(_executor_obj, _executor_clazz,
_executor_stmt_write_id,
hashmap_object);
- env->DeleteLocalRef(hashmap_object);
+ env->DeleteGlobalRef(hashmap_object);
RETURN_ERROR_IF_EXC(env);
*num_rows_sent = block->rows();
return Status::OK();
@@ -396,7 +407,8 @@ Status JdbcConnector::_register_func_id(JNIEnv* env) {
return Status::OK();
}
-jobject JdbcConnector::_get_reader_params(Block* block, JNIEnv* env, size_t
column_size) {
+Status JdbcConnector::_get_reader_params(Block* block, JNIEnv* env, size_t
column_size,
+ jobject* ans) {
std::ostringstream columns_nullable;
std::ostringstream columns_replace_string;
std::ostringstream required_fields;
@@ -447,7 +459,7 @@ jobject JdbcConnector::_get_reader_params(Block* block,
JNIEnv* env, size_t colu
{"replace_string",
columns_replace_string.str()},
{"required_fields",
required_fields.str()},
{"columns_types",
columns_types.str()}};
- return JniUtil::convert_to_java_map(env, reader_params);
+ return JniUtil::convert_to_java_map(env, reader_params, ans);
}
Status JdbcConnector::_cast_string_to_special(Block* block, JNIEnv* env,
size_t column_size) {
@@ -605,13 +617,17 @@ Status JdbcConnector::_cast_string_to_json(const
SlotDescriptor* slot_desc, Bloc
return Status::OK();
}
-jobject JdbcConnector::_get_java_table_type(JNIEnv* env, TOdbcTableType::type
tableType) {
- jclass enumClass =
env->FindClass("org/apache/doris/thrift/TOdbcTableType");
- jmethodID findByValueMethod = env->GetStaticMethodID(
- enumClass, "findByValue",
"(I)Lorg/apache/doris/thrift/TOdbcTableType;");
- jobject javaEnumObj =
- env->CallStaticObjectMethod(enumClass, findByValueMethod,
static_cast<jint>(tableType));
- return javaEnumObj;
+Status JdbcConnector::_get_java_table_type(JNIEnv* env, TOdbcTableType::type
table_type,
+ jobject* java_enum_obj) {
+ jclass enum_class =
env->FindClass("org/apache/doris/thrift/TOdbcTableType");
+ jmethodID find_by_value_method = env->GetStaticMethodID(
+ enum_class, "findByValue",
"(I)Lorg/apache/doris/thrift/TOdbcTableType;");
+ jobject java_enum_local_obj = env->CallStaticObjectMethod(enum_class,
find_by_value_method,
+
static_cast<jint>(table_type));
+ RETURN_ERROR_IF_EXC(env);
+ RETURN_IF_ERROR(JniUtil::LocalToGlobalRef(env, java_enum_local_obj,
java_enum_obj));
+ env->DeleteLocalRef(java_enum_local_obj);
+ return Status::OK();
}
std::string JdbcConnector::_get_real_url(const std::string& url) {
diff --git a/be/src/vec/exec/vjdbc_connector.h
b/be/src/vec/exec/vjdbc_connector.h
index a09d390dc7c..3505d830a36 100644
--- a/be/src/vec/exec/vjdbc_connector.h
+++ b/be/src/vec/exec/vjdbc_connector.h
@@ -127,7 +127,7 @@ protected:
private:
Status _register_func_id(JNIEnv* env);
- jobject _get_reader_params(Block* block, JNIEnv* env, size_t column_size);
+ Status _get_reader_params(Block* block, JNIEnv* env, size_t column_size,
jobject* ans);
Status _cast_string_to_special(Block* block, JNIEnv* env, size_t
column_size);
Status _cast_string_to_hll(const SlotDescriptor* slot_desc, Block* block,
int column_index,
@@ -136,7 +136,9 @@ private:
int rows);
Status _cast_string_to_json(const SlotDescriptor* slot_desc, Block* block,
int column_index,
int rows);
- jobject _get_java_table_type(JNIEnv* env, TOdbcTableType::type tableType);
+
+ Status _get_java_table_type(JNIEnv* env, TOdbcTableType::type table_type,
+ jobject* java_enum_obj);
std::string _get_real_url(const std::string& url);
diff --git a/be/src/vec/exprs/table_function/udf_table_function.cpp
b/be/src/vec/exprs/table_function/udf_table_function.cpp
index bb794737a3d..0a51cd6a54d 100644
--- a/be/src/vec/exprs/table_function/udf_table_function.cpp
+++ b/be/src/vec/exprs/table_function/udf_table_function.cpp
@@ -115,7 +115,8 @@ Status UDFTableFunction::process_init(Block* block,
RuntimeState* state) {
{"required_fields", input_table_schema.first},
{"columns_types", input_table_schema.second}};
- jobject input_map = JniUtil::convert_to_java_map(env, input_params);
+ jobject input_map = nullptr;
+ RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, input_params,
&input_map));
_array_result_column = _return_type->create_column();
_result_column_idx = block->columns();
block->insert({_array_result_column, _return_type, "res"});
@@ -125,13 +126,16 @@ Status UDFTableFunction::process_init(Block* block,
RuntimeState* state) {
{"required_fields",
output_table_schema.first},
{"columns_types",
output_table_schema.second}};
- jobject output_map = JniUtil::convert_to_java_map(env, output_params);
+ jobject output_map = nullptr;
+ RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, output_params,
&output_map));
DCHECK(_jni_ctx != nullptr);
DCHECK(_jni_ctx->executor != nullptr);
long output_address = env->CallLongMethod(_jni_ctx->executor,
_jni_ctx->executor_evaluate_id,
input_map, output_map);
- env->DeleteLocalRef(input_map);
- env->DeleteLocalRef(output_map);
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteGlobalRef(input_map);
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteGlobalRef(output_map);
RETURN_ERROR_IF_EXC(env);
RETURN_IF_ERROR(JniConnector::fill_block(block, {_result_column_idx},
output_address));
block->erase(_result_column_idx);
diff --git a/be/src/vec/exprs/table_function/udf_table_function.h
b/be/src/vec/exprs/table_function/udf_table_function.h
index b0937198467..88427d7a257 100644
--- a/be/src/vec/exprs/table_function/udf_table_function.h
+++ b/be/src/vec/exprs/table_function/udf_table_function.h
@@ -77,7 +77,9 @@ private:
return status;
}
env->CallNonvirtualVoidMethodA(executor, executor_cl,
executor_close_id, nullptr);
+ RETURN_ERROR_IF_EXC(env);
env->DeleteGlobalRef(executor);
+ RETURN_ERROR_IF_EXC(env);
env->DeleteGlobalRef(executor_cl);
RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
is_closed = true;
diff --git a/be/src/vec/functions/function_java_udf.cpp
b/be/src/vec/functions/function_java_udf.cpp
index fd55cdaddb2..5136081cee6 100644
--- a/be/src/vec/functions/function_java_udf.cpp
+++ b/be/src/vec/functions/function_java_udf.cpp
@@ -105,19 +105,23 @@ Status JavaFunctionCall::execute_impl(FunctionContext*
context, Block& block,
{"meta_address", std::to_string((long)input_table.get())},
{"required_fields", input_table_schema.first},
{"columns_types", input_table_schema.second}};
- jobject input_map = JniUtil::convert_to_java_map(env, input_params);
+ jobject input_map = nullptr;
+ RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, input_params,
&input_map));
auto output_table_schema = JniConnector::parse_table_schema(&block,
{result}, true);
std::string output_nullable =
block.get_by_position(result).type->is_nullable() ? "true" :
"false";
std::map<String, String> output_params = {{"is_nullable", output_nullable},
{"required_fields",
output_table_schema.first},
{"columns_types",
output_table_schema.second}};
- jobject output_map = JniUtil::convert_to_java_map(env, output_params);
+ jobject output_map = nullptr;
+ RETURN_IF_ERROR(JniUtil::convert_to_java_map(env, output_params,
&output_map));
long output_address = env->CallLongMethod(jni_ctx->executor,
jni_ctx->executor_evaluate_id,
input_map, output_map);
- env->DeleteLocalRef(input_map);
- env->DeleteLocalRef(output_map);
- RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteGlobalRef(input_map);
+ RETURN_ERROR_IF_EXC(env);
+ env->DeleteGlobalRef(output_map);
+ RETURN_ERROR_IF_EXC(env);
return JniConnector::fill_block(&block, {result}, output_address);
}
diff --git a/be/src/vec/functions/function_java_udf.h
b/be/src/vec/functions/function_java_udf.h
index e35fc67881a..4c358c71bc6 100644
--- a/be/src/vec/functions/function_java_udf.h
+++ b/be/src/vec/functions/function_java_udf.h
@@ -144,7 +144,9 @@ private:
return status;
}
env->CallNonvirtualVoidMethodA(executor, executor_cl,
executor_close_id, nullptr);
+ RETURN_ERROR_IF_EXC(env);
env->DeleteGlobalRef(executor);
+ RETURN_ERROR_IF_EXC(env);
env->DeleteGlobalRef(executor_cl);
RETURN_IF_ERROR(JniUtil::GetJniExceptionMsg(env));
is_closed = true;
diff --git a/regression-test/pipeline/external/conf/be.conf
b/regression-test/pipeline/external/conf/be.conf
index 61ba46218ec..4e38d398899 100644
--- a/regression-test/pipeline/external/conf/be.conf
+++ b/regression-test/pipeline/external/conf/be.conf
@@ -20,10 +20,10 @@ CUR_DATE=`date +%Y%m%d-%H%M%S`
PPROF_TMPDIR="$DORIS_HOME/log/"
# For jdk 8
-JAVA_OPTS="-Xmx2048m -DlogPath=$DORIS_HOME/log/jni.log
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE -XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives
-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true"
+JAVA_OPTS="-Xcheck:jni -Xmx2048m -DlogPath=$DORIS_HOME/log/jni.log
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE -XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives
-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true"
# For jdk 17, this JAVA_OPTS will be used as default JVM options
-JAVA_OPTS_FOR_JDK_17="-Xmx2048m -DlogPath=$DORIS_HOME/log/jni.log
-Xlog:gc*:$DORIS_HOME/log/be.gc.log.$CUR_DATE:time,uptime:filecount=10,filesize=50M
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives
-XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
--add-opens=java.base/java.io=AL [...]
+JAVA_OPTS_FOR_JDK_17="-Xcheck:jni -Xmx2048m -DlogPath=$DORIS_HOME/log/jni.log
-Xlog:gc*:$DORIS_HOME/log/be.gc.log.$CUR_DATE:time,uptime:filecount=10,filesize=50M
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives
-XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.bas [...]
# Set your own JAVA_HOME
# JAVA_HOME=/path/to/jdk/
diff --git a/regression-test/pipeline/p0/conf/be.conf
b/regression-test/pipeline/p0/conf/be.conf
index f73fa0dafdf..264fded9dc6 100644
--- a/regression-test/pipeline/p0/conf/be.conf
+++ b/regression-test/pipeline/p0/conf/be.conf
@@ -20,10 +20,10 @@ CUR_DATE=`date +%Y%m%d-%H%M%S`
PPROF_TMPDIR="$DORIS_HOME/log/"
# For jdk 8
-JAVA_OPTS="-Xmx1024m -DlogPath=$DORIS_HOME/log/jni.log
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE -XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives
-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true"
+JAVA_OPTS="-Xcheck:jni -Xmx1024m -DlogPath=$DORIS_HOME/log/jni.log
-Xloggc:$DORIS_HOME/log/be.gc.log.$CUR_DATE -XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=50M
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives
-Dcom.mysql.cj.disableAbandonedConnectionCleanup=true"
# For jdk 17, this JAVA_OPTS will be used as default JVM options
-JAVA_OPTS_FOR_JDK_17="-Xmx1024m -DlogPath=$DORIS_HOME/log/jni.log
-Xlog:gc*:$DORIS_HOME/log/be.gc.log.$CUR_DATE:time,uptime:filecount=10,filesize=50M
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives
-XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
--add-opens=java.base/java.io=AL [...]
+JAVA_OPTS_FOR_JDK_17="-Xcheck:jni -Xmx1024m -DlogPath=$DORIS_HOME/log/jni.log
-Xlog:gc*:$DORIS_HOME/log/be.gc.log.$CUR_DATE:time,uptime:filecount=10,filesize=50M
-Djavax.security.auth.useSubjectCredsOnly=false -Dsun.security.krb5.debug=true
-Dsun.java.command=DorisBE -XX:-CriticalJNINatives
-XX:+IgnoreUnrecognizedVMOptions --add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.bas [...]
# Set your own JAVA_HOME
# JAVA_HOME=/path/to/jdk/
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]