This is an automated email from the ASF dual-hosted git repository.

Gabriel39 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 20bb1bb4cab [fix](be) Keep Paimon JNI predicate compatibility (#65328)
20bb1bb4cab is described below

commit 20bb1bb4cabdd2904714fb0bd296d474a5013ac2
Author: Gabriel <[email protected]>
AuthorDate: Wed Jul 8 12:46:24 2026 +0800

    [fix](be) Keep Paimon JNI predicate compatibility (#65328)
    
    Format V2 Paimon JNI reader now falls back to legacy split-level
    paimon_predicate when scan-level predicate is missing or empty. Added BE
    unit coverage for scan priority, legacy fallback, and missing predicate
    failure. Validation: build-support/clang-format.sh passed;
    ./run-be-ut.sh --run --filter=PaimonJniReaderTest* was attempted but
    local CMake is blocked by incomplete thirdparty/installed dependencies
    after missing Protobuf library.
---
 be/src/format_v2/jni/paimon_jni_reader.cpp       |  22 +++-
 be/test/format_v2/jni/paimon_jni_reader_test.cpp | 127 +++++++++++++++++++++++
 2 files changed, 145 insertions(+), 4 deletions(-)

diff --git a/be/src/format_v2/jni/paimon_jni_reader.cpp 
b/be/src/format_v2/jni/paimon_jni_reader.cpp
index 3902093b7c8..ca1e602cdfe 100644
--- a/be/src/format_v2/jni/paimon_jni_reader.cpp
+++ b/be/src/format_v2/jni/paimon_jni_reader.cpp
@@ -32,6 +32,18 @@ constexpr std::string_view DORIS_ENABLE_JNI_IO_MANAGER = 
"doris.enable_jni_io_ma
 constexpr std::string_view DORIS_JNI_IO_MANAGER_TMP_DIR = 
"doris.jni_io_manager.tmp_dir";
 constexpr std::string_view PAIMON_JNI_SCANNER_IO_TMP_DIR = 
"paimon_jni_scanner_io_tmp";
 
+const std::string* get_paimon_predicate(const TFileScanRangeParams* 
scan_params,
+                                        const TPaimonFileDesc& paimon_params) {
+    if (scan_params != nullptr && scan_params->__isset.paimon_predicate &&
+        !scan_params->paimon_predicate.empty()) {
+        return &scan_params->paimon_predicate;
+    }
+    if (paimon_params.__isset.paimon_predicate && 
!paimon_params.paimon_predicate.empty()) {
+        return &paimon_params.paimon_predicate;
+    }
+    return nullptr;
+}
+
 } // namespace
 
 Status PaimonJniReader::validate_scan_range(const TFileRangeDesc& range) const 
{
@@ -59,7 +71,7 @@ Status PaimonJniReader::validate_scan_range(const 
TFileRangeDesc& range) const {
                 "missing serialized_table for paimon jni reader, possibly 
caused by FE/BE "
                 "protocol mismatch");
     }
-    if (!_scan_params->__isset.paimon_predicate || 
_scan_params->paimon_predicate.empty()) {
+    if (get_paimon_predicate(_scan_params, 
range.table_format_params.paimon_params) == nullptr) {
         return Status::InternalError(
                 "missing paimon_predicate for paimon jni reader, possibly 
caused by FE/BE "
                 "protocol mismatch");
@@ -77,8 +89,10 @@ Status 
PaimonJniReader::build_scanner_params(std::map<std::string, std::string>*
     params->clear();
 
     const auto& paimon_params = 
_current_range.table_format_params.paimon_params;
+    const auto* paimon_predicate = get_paimon_predicate(_scan_params, 
paimon_params);
+    DORIS_CHECK(paimon_predicate != nullptr);
     (*params)["paimon_split"] = paimon_params.paimon_split;
-    (*params)["paimon_predicate"] = _scan_params->paimon_predicate;
+    (*params)["paimon_predicate"] = *paimon_predicate;
     (*params)["serialized_table"] = _scan_params->serialized_table;
 
     if (_scan_params->__isset.paimon_options && 
!_scan_params->paimon_options.empty()) {
@@ -106,8 +120,8 @@ Status 
PaimonJniReader::build_scanner_params(std::map<std::string, std::string>*
         }
     }
     // TODO: Remove legacy split-level paimon_predicate, paimon_options and 
hadoop_conf from thrift
-    // after all readers stop using them. Format V2 Paimon JNI consumes the 
scan-level fields
-    // planned by current FE and intentionally does not fall back to 
deprecated split-level fields.
+    // after all readers stop using them. Predicate keeps the split-level 
fallback for rolling
+    // upgrade compatibility with old FE paths that did not send scan-level 
paimon_predicate.
     return Status::OK();
 }
 
diff --git a/be/test/format_v2/jni/paimon_jni_reader_test.cpp 
b/be/test/format_v2/jni/paimon_jni_reader_test.cpp
new file mode 100644
index 00000000000..08fd333abd3
--- /dev/null
+++ b/be/test/format_v2/jni/paimon_jni_reader_test.cpp
@@ -0,0 +1,127 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "format_v2/jni/paimon_jni_reader.h"
+
+#include <gtest/gtest.h>
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "format_v2/table_reader.h"
+#include "gen_cpp/PlanNodes_types.h"
+
+namespace doris::format::paimon {
+namespace {
+
+TFileRangeDesc make_paimon_jni_range() {
+    TFileRangeDesc range;
+    TTableFormatFileDesc table_format_params;
+    table_format_params.__set_table_format_type("paimon");
+    TPaimonFileDesc paimon_params;
+    paimon_params.__set_reader_type(TPaimonReaderType::PAIMON_JNI);
+    paimon_params.__set_paimon_split("serialized-split");
+    table_format_params.__set_paimon_params(std::move(paimon_params));
+    range.__set_table_format_params(std::move(table_format_params));
+    return range;
+}
+
+TFileScanRangeParams make_scan_params() {
+    TFileScanRangeParams scan_params;
+    scan_params.__set_serialized_table("serialized-table");
+    return scan_params;
+}
+
+Status init_reader(PaimonJniReader* reader, TFileScanRangeParams* scan_params) 
{
+    return reader->init({
+            .projected_columns = {},
+            .conjuncts = {},
+            .format = FileFormat::JNI,
+            .scan_params = scan_params,
+            .io_ctx = nullptr,
+            .runtime_state = nullptr,
+            .scanner_profile = nullptr,
+    });
+}
+
+Status build_params(PaimonJniReader* reader, const TFileRangeDesc& range,
+                    std::map<std::string, std::string>* params) {
+    reader->_current_range = range;
+    return reader->build_scanner_params(params);
+}
+
+TEST(PaimonJniReaderTest, UsesScanLevelPredicateBeforeLegacySplitPredicate) {
+    auto range = make_paimon_jni_range();
+    
range.table_format_params.paimon_params.__set_paimon_predicate("legacy-predicate");
+
+    auto scan_params = make_scan_params();
+    scan_params.__set_paimon_predicate("scan-predicate");
+
+    PaimonJniReader reader;
+    ASSERT_TRUE(init_reader(&reader, &scan_params).ok());
+    ASSERT_TRUE(reader.validate_scan_range(range).ok());
+
+    std::map<std::string, std::string> params;
+    ASSERT_TRUE(build_params(&reader, range, &params).ok());
+    EXPECT_EQ(params["paimon_predicate"], "scan-predicate");
+}
+
+TEST(PaimonJniReaderTest, 
FallsBackToLegacySplitPredicateWhenScanPredicateIsMissing) {
+    auto range = make_paimon_jni_range();
+    
range.table_format_params.paimon_params.__set_paimon_predicate("legacy-predicate");
+
+    auto scan_params = make_scan_params();
+
+    PaimonJniReader reader;
+    ASSERT_TRUE(init_reader(&reader, &scan_params).ok());
+    ASSERT_TRUE(reader.validate_scan_range(range).ok());
+
+    std::map<std::string, std::string> params;
+    ASSERT_TRUE(build_params(&reader, range, &params).ok());
+    EXPECT_EQ(params["paimon_predicate"], "legacy-predicate");
+}
+
+TEST(PaimonJniReaderTest, 
FallsBackToLegacySplitPredicateWhenScanPredicateIsEmpty) {
+    auto range = make_paimon_jni_range();
+    
range.table_format_params.paimon_params.__set_paimon_predicate("legacy-predicate");
+
+    auto scan_params = make_scan_params();
+    scan_params.__set_paimon_predicate("");
+
+    PaimonJniReader reader;
+    ASSERT_TRUE(init_reader(&reader, &scan_params).ok());
+    ASSERT_TRUE(reader.validate_scan_range(range).ok());
+
+    std::map<std::string, std::string> params;
+    ASSERT_TRUE(build_params(&reader, range, &params).ok());
+    EXPECT_EQ(params["paimon_predicate"], "legacy-predicate");
+}
+
+TEST(PaimonJniReaderTest, RejectsMissingPredicateFromBothProtocolLocations) {
+    const auto range = make_paimon_jni_range();
+    auto scan_params = make_scan_params();
+
+    PaimonJniReader reader;
+    ASSERT_TRUE(init_reader(&reader, &scan_params).ok());
+    const auto status = reader.validate_scan_range(range);
+    EXPECT_FALSE(status.ok());
+    EXPECT_NE(status.to_string().find("missing paimon_predicate"), 
std::string::npos);
+}
+
+} // namespace
+} // namespace doris::format::paimon


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to