From 8f0d728d687d8e7209df94c7ca5d835052545dba Mon Sep 17 00:00:00 2001 From: linzhenqi Date: Sat, 30 May 2026 00:41:16 +0800 Subject: [PATCH] [Enhancement](udf) Do not check file when inline code exists --- .../plans/commands/CreateFunctionCommand.java | 7 +++--- .../test_pythonudf_file_protocol.out | 2 ++ .../test_pythonudf_file_protocol.groovy | 22 +++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateFunctionCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateFunctionCommand.java index bc5edcbb59ba52..eecf685eeedb3e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateFunctionCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/CreateFunctionCommand.java @@ -329,11 +329,10 @@ private void analyzeCommon(ConnectContext ctx) throws AnalysisException { userFile = properties.getOrDefault(FILE_KEY, properties.get(OBJECT_FILE_KEY)); originalUserFile = userFile; // Keep original jar name for BE - // Convert userFile to realUrl only for FE checksum calculation - if (!Strings.isNullOrEmpty(userFile) && binaryType != Function.BinaryType.RPC) { + // Inline Python code is authoritative. Keep FILE in metadata for replay, but do not load or validate it here. + if (Strings.isNullOrEmpty(functionCode) && !Strings.isNullOrEmpty(userFile) + && binaryType != Function.BinaryType.RPC) { userFile = getRealUrl(userFile); - } - if (!Strings.isNullOrEmpty(userFile) && binaryType != Function.BinaryType.RPC) { try { computeObjectChecksum(); } catch (IOException | NoSuchAlgorithmException e) { diff --git a/regression-test/data/pythonudf_p0/test_pythonudf_file_protocol.out b/regression-test/data/pythonudf_p0/test_pythonudf_file_protocol.out index 8d1d3a594e5e2b..d496aaeeb60440 100644 --- a/regression-test/data/pythonudf_p0/test_pythonudf_file_protocol.out +++ b/regression-test/data/pythonudf_p0/test_pythonudf_file_protocol.out @@ -20,3 +20,5 @@ true 3 30 31 python p****n 4 40 41 doris d***s +-- !select_file_inline_precedence -- +1007 diff --git a/regression-test/suites/pythonudf_p0/test_pythonudf_file_protocol.groovy b/regression-test/suites/pythonudf_p0/test_pythonudf_file_protocol.groovy index bbea4b94bf2014..65d7a3533eeb2a 100644 --- a/regression-test/suites/pythonudf_p0/test_pythonudf_file_protocol.groovy +++ b/regression-test/suites/pythonudf_p0/test_pythonudf_file_protocol.groovy @@ -117,6 +117,28 @@ suite("test_pythonudf_file_protocol") { FROM file_protocol_test_table ORDER BY id; """ + + // Inline code must take precedence over FILE. Use a missing FILE path so the + // test fails if FE or BE tries to validate/load it as a module. + sql """ DROP FUNCTION IF EXISTS py_file_inline_precedence(INT); """ + sql """ + CREATE FUNCTION py_file_inline_precedence(INT) + RETURNS INT + PROPERTIES ( + "type" = "PYTHON_UDF", + "file" = "file://${context.file.parent}/udf_scripts/missing_inline_precedence.zip", + "symbol" = "evaluate", + "runtime_version" = "${runtime_version}" + ) + AS \$\$ +def evaluate(arg): + if arg is None: + return None + return int(arg + 1000) +\$\$; + """ + + qt_select_file_inline_precedence """ SELECT py_file_inline_precedence(7) AS result; """ } finally { try_sql("DROP FUNCTION IF EXISTS py_file_int_add(INT);")