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 b4466bc35bf branch-3.1: [fix](plugin) fix plugin dir compatible issue
(#56060)
b4466bc35bf is described below
commit b4466bc35bfc45e7441e354a4b4323088f79b645
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Tue Sep 16 23:01:14 2025 -0700
branch-3.1: [fix](plugin) fix plugin dir compatible issue (#56060)
Followup #52921
Some code is missing after cherry-pick
When upgrading from 3.0.x to 3.1.x, if user put jdbc driver jar under
`${DORIS_HOME}/jdbc_drivers`,
the system will fail to find the jar, which is unexpected.
For compatibility, the system should check both
`${DORIS_HOME}/jdbc_drivers`(old) and
`${DORIS_HOME}/plugins/jdbc_drivers`(new) to find the jar.
This PR fix it.
Only for branch-3.1. No issue on master branch
---
be/src/common/config.cpp | 3 +
be/src/common/config.h | 3 +
be/src/runtime/user_function_cache.cpp | 6 +-
be/src/runtime/user_function_cache.h | 2 -
be/src/util/path_util.cpp | 46 +++++++++++++
be/src/util/path_util.h | 16 +++++
be/src/vec/exec/vjdbc_connector.cpp | 11 +--
be/src/vec/exec/vjdbc_connector.h | 2 -
be/test/util/path_util_test.cpp | 119 +++++++++++++++++++++++++++++++++
9 files changed, 195 insertions(+), 13 deletions(-)
diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp
index 243cd65351a..931130994da 100644
--- a/be/src/common/config.cpp
+++ b/be/src/common/config.cpp
@@ -54,6 +54,9 @@ DEFINE_String(custom_config_dir, "${DORIS_HOME}/conf");
// Dir of jdbc drivers
DEFINE_String(jdbc_drivers_dir, "${DORIS_HOME}/plugins/jdbc_drivers");
+// Dir of java udf
+DEFINE_String(java_udf_dir, "${DORIS_HOME}/plugins/java_udf");
+
// cluster id
DEFINE_Int32(cluster_id, "-1");
// port on which BackendService is exported
diff --git a/be/src/common/config.h b/be/src/common/config.h
index 55591fc36c7..2b3691c9186 100644
--- a/be/src/common/config.h
+++ b/be/src/common/config.h
@@ -88,6 +88,9 @@ DECLARE_String(custom_config_dir);
// Dir of jdbc drivers
DECLARE_String(jdbc_drivers_dir);
+// Dir of java udf
+DECLARE_String(java_udf_dir);
+
// cluster id
DECLARE_Int32(cluster_id);
// port on which BackendService is exported
diff --git a/be/src/runtime/user_function_cache.cpp
b/be/src/runtime/user_function_cache.cpp
index e058b76ad33..5ec3c633d15 100644
--- a/be/src/runtime/user_function_cache.cpp
+++ b/be/src/runtime/user_function_cache.cpp
@@ -42,6 +42,7 @@
#include "runtime/exec_env.h"
#include "util/dynamic_util.h"
#include "util/md5.h"
+#include "util/path_util.h"
#include "util/string_util.h"
namespace doris {
@@ -271,10 +272,12 @@ Status UserFunctionCache::_download_lib(const
std::string& url,
return Status::InternalError("fail to open file");
}
+ std::string udf_path =
+ doris::path_util::get_real_plugin_url(url,
doris::config::java_udf_dir, "java_udf");
Md5Digest digest;
HttpClient client;
int64_t file_size = 0;
- RETURN_IF_ERROR(client.init(url));
+ RETURN_IF_ERROR(client.init(udf_path));
Status status;
auto download_cb = [&status, &tmp_file, &fp, &digest, &file_size](const
void* data,
size_t
length) {
@@ -382,4 +385,5 @@ std::vector<std::string>
UserFunctionCache::_split_string_by_checksum(const std:
return result;
}
+
} // namespace doris
diff --git a/be/src/runtime/user_function_cache.h
b/be/src/runtime/user_function_cache.h
index 2537d9376ec..93759c261e2 100644
--- a/be/src/runtime/user_function_cache.h
+++ b/be/src/runtime/user_function_cache.h
@@ -75,8 +75,6 @@ private:
std::string _get_file_name_from_url(const std::string& url) const;
std::vector<std::string> _split_string_by_checksum(const std::string&
file);
- std::string _check_and_return_default_driver_url(const std::string& url);
-
private:
std::string _lib_dir;
void* _current_process_handle = nullptr;
diff --git a/be/src/util/path_util.cpp b/be/src/util/path_util.cpp
index e05b9371e49..4b6f6adcbed 100644
--- a/be/src/util/path_util.cpp
+++ b/be/src/util/path_util.cpp
@@ -20,6 +20,10 @@
// Use the POSIX version of dirname(3). See `man 3 dirname`
#include <libgen.h>
+#include <cstdlib>
+#include <filesystem>
+
+#include "common/config.h"
#include "gutil/strings/split.h"
#include "gutil/strings/strip.h"
@@ -64,5 +68,47 @@ std::string file_extension(const string& path) {
return pos == string::npos ? "" : file_name.substr(pos);
}
+std::string get_real_plugin_url(const std::string& url, const std::string&
plugin_dir_config_value,
+ const std::string& plugin_dir_name, const
std::string& doris_home) {
+ if (url.find(":/") == std::string::npos) {
+ return check_and_return_default_plugin_url(url,
plugin_dir_config_value, plugin_dir_name,
+ doris_home);
+ }
+ return url;
+}
+
+std::string check_and_return_default_plugin_url(const std::string& url,
+ const std::string&
plugin_dir_config_value,
+ const std::string&
plugin_dir_name,
+ const std::string& doris_home)
{
+ std::string home_dir = doris_home;
+ if (home_dir.empty()) {
+ const char* env_home = std::getenv("DORIS_HOME");
+ if (env_home) {
+ home_dir = std::string(env_home);
+ } else {
+ return "file://" + plugin_dir_config_value + "/" + url;
+ }
+ }
+
+ std::string default_url = home_dir + "/plugins/" + plugin_dir_name;
+ std::string default_old_url = home_dir + "/" + plugin_dir_name;
+
+ if (plugin_dir_config_value == default_url) {
+ // If true, which means user does not set `jdbc_drivers_dir` and use
the default one.
+ // Because in 2.1.8, we change the default value of `jdbc_drivers_dir`
+ // from `DORIS_HOME/jdbc_drivers` to `DORIS_HOME/plugins/jdbc_drivers`,
+ // so we need to check the old default dir for compatibility.
+ std::filesystem::path file = default_url + "/" + url;
+ if (std::filesystem::exists(file)) {
+ return "file://" + default_url + "/" + url;
+ } else {
+ return "file://" + default_old_url + "/" + url;
+ }
+ } else {
+ return "file://" + plugin_dir_config_value + "/" + url;
+ }
+}
+
} // namespace path_util
} // namespace doris
diff --git a/be/src/util/path_util.h b/be/src/util/path_util.h
index ee68122f4fa..61231e6239d 100644
--- a/be/src/util/path_util.h
+++ b/be/src/util/path_util.h
@@ -55,5 +55,21 @@ std::string base_name(const std::string& path);
// NOTE: path can be either one file's full path or only file name
std::string file_extension(const std::string& path);
+// Get the real URL for plugins (e.g., JDBC drivers). If the URL doesn't
contain ":/",
+// it will be treated as a relative path and converted to a file:// URL using
provided dirs.
+// plugin_dir_config_value is the configured plugin dir; plugin_dir_name is
the dir name (e.g. "jdbc_drivers").
+// doris_home is optional; if empty, will use DORIS_HOME environment variable.
+std::string get_real_plugin_url(const std::string& url, const std::string&
plugin_dir_config_value,
+ const std::string& plugin_dir_name,
+ const std::string& doris_home = "");
+
+// Check and return the default plugin URL using provided directories.
+// plugin_dir_config_value is the configured drivers dir; plugin_dir_name is
dir name.
+// doris_home is optional; if empty, will use DORIS_HOME environment variable.
+std::string check_and_return_default_plugin_url(const std::string& url,
+ const std::string&
plugin_dir_config_value,
+ const std::string&
plugin_dir_name,
+ const std::string& doris_home
= "");
+
} // namespace path_util
} // namespace doris
diff --git a/be/src/vec/exec/vjdbc_connector.cpp
b/be/src/vec/exec/vjdbc_connector.cpp
index 17e4781a5a6..d4cf31f4f78 100644
--- a/be/src/vec/exec/vjdbc_connector.cpp
+++ b/be/src/vec/exec/vjdbc_connector.cpp
@@ -36,6 +36,7 @@
#include "runtime/types.h"
#include "runtime/user_function_cache.h"
#include "util/jni-util.h"
+#include "util/path_util.h"
#include "util/runtime_profile.h"
#include "vec/columns/column_nullable.h"
#include "vec/core/block.h"
@@ -126,7 +127,8 @@ Status JdbcConnector::open(RuntimeState* state, bool read) {
// Add a scoped cleanup jni reference object. This cleans up local refs
made below.
JniLocalFrame jni_frame;
{
- std::string driver_path = _get_real_url(_conn_param.driver_path);
+ std::string driver_path = doris::path_util::get_real_plugin_url(
+ _conn_param.driver_path, doris::config::jdbc_drivers_dir,
"jdbc_drivers", "");
TJdbcExecutorCtorParams ctor_params;
ctor_params.__set_statement(_sql_str);
@@ -633,11 +635,4 @@ Status JdbcConnector::_get_java_table_type(JNIEnv* env,
TOdbcTableType::type tab
return Status::OK();
}
-std::string JdbcConnector::_get_real_url(const std::string& url) {
- if (url.find(":/") == std::string::npos) {
- return "file://" + config::jdbc_drivers_dir + "/" + url;
- }
- return url;
-}
-
} // namespace doris::vectorized
diff --git a/be/src/vec/exec/vjdbc_connector.h
b/be/src/vec/exec/vjdbc_connector.h
index 8838ce5984d..b514389b5da 100644
--- a/be/src/vec/exec/vjdbc_connector.h
+++ b/be/src/vec/exec/vjdbc_connector.h
@@ -141,8 +141,6 @@ private:
Status _get_java_table_type(JNIEnv* env, TOdbcTableType::type table_type,
jobject* java_enum_obj);
- std::string _get_real_url(const std::string& url);
-
bool _closed = false;
jclass _executor_factory_clazz;
jclass _executor_clazz;
diff --git a/be/test/util/path_util_test.cpp b/be/test/util/path_util_test.cpp
index 8806febb133..3ec95c5a1ac 100644
--- a/be/test/util/path_util_test.cpp
+++ b/be/test/util/path_util_test.cpp
@@ -20,6 +20,9 @@
#include <gtest/gtest-message.h>
#include <gtest/gtest-test-part.h>
+#include <cstdlib>
+#include <filesystem>
+#include <fstream>
#include <string>
#include <vector>
@@ -99,4 +102,120 @@ TEST(TestPathUtil, file_extension_test) {
EXPECT_EQ(".", path_util::file_extension("a.b.c."));
}
+// Helpers for plugin URL tests
+namespace {
+
+std::string create_temp_home() {
+ namespace fs = std::filesystem;
+ fs::path base = fs::temp_directory_path() / "doris_path_util_test";
+ fs::create_directories(base);
+ // ensure unique subdir per test run
+ fs::path home = base / std::to_string(reinterpret_cast<uintptr_t>(&base));
+ fs::create_directories(home);
+ return home.string();
+}
+
+void touch_file(const std::string& dir, const std::string& filename) {
+ namespace fs = std::filesystem;
+ fs::create_directories(dir);
+ std::ofstream ofs(fs::path(dir) / filename, std::ios::binary);
+ ofs << "x";
+}
+
+} // namespace
+
+TEST(TestPathUtil, get_real_plugin_url_absolute_passthrough) {
+ // absolute style URLs containing ":/" should be returned as-is
+ EXPECT_EQ("http://example.com/a.jar",
+ path_util::get_real_plugin_url("http://example.com/a.jar",
"/any/dir", "jdbc_drivers",
+ ""));
+ EXPECT_EQ("file:///opt/driver/a.jar",
+ path_util::get_real_plugin_url("file:///opt/driver/a.jar",
"/any/dir", "jdbc_drivers",
+ ""));
+}
+
+TEST(TestPathUtil,
check_and_return_default_plugin_url_prefers_new_default_when_exists) {
+ namespace fs = std::filesystem;
+ std::string home = create_temp_home();
+ std::string plugin_name = "jdbc_drivers";
+ std::string default_new = home + "/plugins/" + plugin_name;
+ std::string default_old = home + "/" + plugin_name;
+ std::string fname = "drv.jar";
+
+ touch_file(default_new, fname);
+
+ std::string expected = "file://" + default_new + "/" + fname;
+ EXPECT_EQ(expected, path_util::check_and_return_default_plugin_url(fname,
default_new,
+
plugin_name, home));
+}
+
+TEST(TestPathUtil,
check_and_return_default_plugin_url_falls_back_to_old_default) {
+ std::string home = create_temp_home();
+ std::string plugin_name = "jdbc_drivers";
+ std::string default_new = home + "/plugins/" + plugin_name;
+ std::string default_old = home + "/" + plugin_name;
+ std::string fname = "drv.jar";
+
+ // create only old default file
+ touch_file(default_old, fname);
+
+ std::string expected = "file://" + default_old + "/" + fname;
+ EXPECT_EQ(expected, path_util::check_and_return_default_plugin_url(fname,
default_new,
+
plugin_name, home));
+}
+
+TEST(TestPathUtil, check_and_return_default_plugin_url_old_even_if_missing) {
+ std::string home = create_temp_home();
+ std::string plugin_name = "jdbc_drivers";
+ std::string default_new = home + "/plugins/" + plugin_name;
+ std::string default_old = home + "/" + plugin_name;
+ std::string fname = "drv.jar";
+
+ // neither new nor old has the file; should still point to old default
+ std::string expected = "file://" + default_old + "/" + fname;
+ EXPECT_EQ(expected, path_util::check_and_return_default_plugin_url(fname,
default_new,
+
plugin_name, home));
+}
+
+TEST(TestPathUtil, check_and_return_default_plugin_url_custom_config_dir) {
+ std::string home = create_temp_home();
+ std::string plugin_name = "jdbc_drivers";
+ std::string custom_dir = home + "/custom/plugins";
+ std::string fname = "drv.jar";
+ touch_file(custom_dir, fname);
+
+ std::string expected = "file://" + custom_dir + "/" + fname;
+ EXPECT_EQ(expected,
+ path_util::check_and_return_default_plugin_url(fname,
custom_dir, plugin_name, home));
+}
+
+TEST(TestPathUtil, get_real_plugin_url_relative_paths) {
+ std::string home = create_temp_home();
+ std::string plugin_name = "jdbc_drivers";
+ std::string default_new = home + "/plugins/" + plugin_name;
+ std::string default_old = home + "/" + plugin_name;
+ std::string fname = "drv.jar";
+
+ // When new default exists
+ touch_file(default_new, fname);
+ std::string expected_new = "file://" + default_new + "/" + fname;
+ EXPECT_EQ(expected_new, path_util::get_real_plugin_url(fname, default_new,
plugin_name, home));
+
+ // When only old default exists
+ std::string home2 = create_temp_home();
+ std::string default_new2 = home2 + "/plugins/" + plugin_name;
+ std::string default_old2 = home2 + "/" + plugin_name;
+ touch_file(default_old2, fname);
+ std::string expected_old = "file://" + default_old2 + "/" + fname;
+ EXPECT_EQ(expected_old,
+ path_util::get_real_plugin_url(fname, default_new2, plugin_name,
home2));
+
+ // When using a custom configured dir (not equal to default new path)
+ std::string custom_dir = home + "/custom";
+ touch_file(custom_dir, fname);
+ std::string expected_custom = "file://" + custom_dir + "/" + fname;
+ EXPECT_EQ(expected_custom,
+ path_util::get_real_plugin_url(fname, custom_dir, plugin_name,
home));
+}
+
} // namespace doris
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]