Coverage Report

Created: 2026-03-14 20:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/function/function_java_udf.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <gen_cpp/Types_types.h>
21
#include <jni.h>
22
#include <stddef.h>
23
#include <stdint.h>
24
25
#include <functional>
26
#include <memory>
27
28
#include "common/logging.h"
29
#include "common/status.h"
30
#include "core/block/block.h"
31
#include "core/block/column_numbers.h"
32
#include "core/block/columns_with_type_and_name.h"
33
#include "core/data_type/data_type.h"
34
#include "core/types.h"
35
#include "exprs/function/function.h"
36
#include "exprs/function_context.h"
37
#include "util/jni-util.h"
38
39
namespace doris {
40
41
class JavaUdfPreparedFunction : public PreparedFunctionImpl {
42
public:
43
    using execute_call_back = std::function<Status(FunctionContext* context, Block& block,
44
                                                   const ColumnNumbers& arguments, uint32_t result,
45
                                                   size_t input_rows_count)>;
46
47
    explicit JavaUdfPreparedFunction(const execute_call_back& func, const std::string& name)
48
0
            : callback_function(func), name(name) {}
49
50
0
    String get_name() const override { return name; }
51
52
protected:
53
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
54
0
                        uint32_t result, size_t input_rows_count) const override {
55
0
        return callback_function(context, block, arguments, result, input_rows_count);
56
0
    }
57
58
0
    bool use_default_implementation_for_nulls() const override { return false; }
59
60
private:
61
    execute_call_back callback_function;
62
    std::string name;
63
};
64
65
class JavaFunctionCall : public IFunctionBase {
66
public:
67
    JavaFunctionCall(const TFunction& fn, const DataTypes& argument_types,
68
                     const DataTypePtr& return_type);
69
70
    static FunctionBasePtr create(const TFunction& fn, const ColumnsWithTypeAndName& argument_types,
71
0
                                  const DataTypePtr& return_type) {
72
0
        DataTypes data_types(argument_types.size());
73
0
        for (size_t i = 0; i < argument_types.size(); ++i) {
74
0
            data_types[i] = argument_types[i].type;
75
0
        }
76
0
        return std::make_shared<JavaFunctionCall>(fn, data_types, return_type);
77
0
    }
78
79
    /// Get the main function name.
80
0
    String get_name() const override { return fn_.name.function_name; }
81
82
0
    const DataTypes& get_argument_types() const override { return _argument_types; }
83
0
    const DataTypePtr& get_return_type() const override { return _return_type; }
84
85
    PreparedFunctionPtr prepare(FunctionContext* context, const Block& sample_block,
86
0
                                const ColumnNumbers& arguments, uint32_t result) const override {
87
0
        return std::make_shared<JavaUdfPreparedFunction>(
88
0
                [this](auto&& PH1, auto&& PH2, auto&& PH3, auto&& PH4, auto&& PH5) {
89
0
                    return JavaFunctionCall::execute_impl(
90
0
                            std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2),
91
0
                            std::forward<decltype(PH3)>(PH3), std::forward<decltype(PH4)>(PH4),
92
0
                            std::forward<decltype(PH5)>(PH5));
93
0
                },
94
0
                fn_.name.function_name);
95
0
    }
96
97
    Status open(FunctionContext* context, FunctionContext::FunctionStateScope scope) override;
98
99
    Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
100
                        uint32_t result, size_t input_rows_count) const;
101
102
    Status close(FunctionContext* context, FunctionContext::FunctionStateScope scope) override;
103
104
0
    bool is_use_default_implementation_for_constants() const override { return true; }
105
106
0
    bool is_udf_function() const override { return true; }
107
108
private:
109
    const TFunction& fn_;
110
    const DataTypes _argument_types;
111
    const DataTypePtr _return_type;
112
113
    struct JniContext {
114
        // Do not save parent directly, because parent is in VExpr, but jni context is in FunctionContext
115
        // The deconstruct sequence is not determined, it will core.
116
        // JniContext's lifecycle should same with function context, not related with expr
117
118
        Jni::GlobalClass executor_cl;
119
        Jni::MethodId executor_ctor_id;
120
        Jni::MethodId executor_evaluate_id;
121
        Jni::MethodId executor_close_id;
122
        Jni::GlobalObject executor;
123
        bool is_closed = false;
124
        bool open_successes = false;
125
126
0
        JniContext() = default;
127
128
0
        Status close() {
129
0
            if (!open_successes) {
130
0
                LOG_WARNING("maybe open failed, need check the reason");
131
0
                return Status::OK(); //maybe open failed, so can't call some jni
132
0
            }
133
0
            if (is_closed) {
134
0
                return Status::OK();
135
0
            }
136
0
            VLOG_DEBUG << "Free resources for JniContext";
137
0
            JNIEnv* env = nullptr;
138
0
            Status status = Jni::Env::Get(&env);
139
0
            if (!status.ok() || env == nullptr) {
140
0
                LOG(WARNING) << "errors while get jni env " << status;
141
0
                return status;
142
0
            }
143
0
            return executor.call_nonvirtual_void_method(env, executor_cl, executor_close_id).call();
144
0
        }
145
    };
146
};
147
148
} // namespace doris