Coverage Report

Created: 2026-07-20 14:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/information_schema/schema_plugins_scanner.cpp
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
#include "information_schema/schema_plugins_scanner.h"
19
20
#include <utility>
21
22
#include "core/assert_cast.h"
23
#include "core/block/block.h"
24
#include "core/column/column_nullable.h"
25
#include "core/data_type/data_type_factory.hpp"
26
#include "core/string_ref.h"
27
#include "runtime/exec_env.h"
28
#include "runtime/query_context.h"
29
#include "runtime/runtime_state.h"
30
#include "util/client_cache.h"
31
#include "util/thrift_rpc_helper.h"
32
33
namespace doris {
34
35
std::vector<SchemaScanner::ColumnDesc> SchemaPluginsScanner::_s_tbls_columns = {
36
        {"PLUGIN_NAME", TYPE_STRING, sizeof(StringRef), true},
37
        {"PLUGIN_TYPE", TYPE_STRING, sizeof(StringRef), true},
38
        {"PLUGIN_VERSION", TYPE_STRING, sizeof(StringRef), true},
39
        {"SOURCE", TYPE_STRING, sizeof(StringRef), true},
40
        {"DESCRIPTION", TYPE_STRING, sizeof(StringRef), true},
41
};
42
43
SchemaPluginsScanner::SchemaPluginsScanner()
44
0
        : SchemaScanner(_s_tbls_columns, TSchemaTableType::SCH_PLUGINS) {}
45
46
0
Status SchemaPluginsScanner::start(RuntimeState* state) {
47
0
    if (!_is_init) {
48
0
        return Status::InternalError("used before initialized.");
49
0
    }
50
0
    _block_rows_limit = state->batch_size();
51
0
    _rpc_timeout_ms = state->execution_timeout() * 1000;
52
    // Plugins are per-FE local state: ask the FE this session is connected to.
53
0
    auto* query_ctx = state->get_query_ctx();
54
0
    if (query_ctx == nullptr) {
55
0
        return Status::InternalError("query context is null");
56
0
    }
57
0
    _fe_addr = query_ctx->current_connect_fe;
58
0
    return Status::OK();
59
0
}
60
61
0
Status SchemaPluginsScanner::_get_plugins_block_from_fe() {
62
0
    TSchemaTableRequestParams schema_table_request_params;
63
0
    for (int i = 0; i < _s_tbls_columns.size(); i++) {
64
0
        schema_table_request_params.__isset.columns_name = true;
65
0
        schema_table_request_params.columns_name.emplace_back(_s_tbls_columns[i].name);
66
0
    }
67
0
    schema_table_request_params.__set_current_user_ident(*_param->common_param->current_user_ident);
68
69
0
    TFetchSchemaTableDataRequest request;
70
0
    request.__set_schema_table_name(TSchemaTableName::PLUGINS);
71
0
    request.__set_schema_table_params(schema_table_request_params);
72
73
0
    TFetchSchemaTableDataResult result;
74
0
    RETURN_IF_ERROR(ThriftRpcHelper::rpc<FrontendServiceClient>(
75
0
            _fe_addr.hostname, _fe_addr.port,
76
0
            [&request, &result](FrontendServiceConnection& client) {
77
0
                client->fetchSchemaTableData(result, request);
78
0
            },
79
0
            _rpc_timeout_ms));
80
81
0
    Status status(Status::create(result.status));
82
0
    if (!status.ok()) {
83
0
        LOG(WARNING) << "fetch plugins from FE(" << _fe_addr.hostname
84
0
                     << ") failed, errmsg=" << status;
85
0
        return status;
86
0
    }
87
88
0
    std::vector<TRow> result_data = std::move(result.data_batch);
89
0
    if (!result_data.empty()) {
90
0
        auto col_size = result_data[0].column_value.size();
91
0
        if (col_size != _s_tbls_columns.size()) {
92
0
            return Status::InternalError<false>("plugins schema is not match for FE and BE");
93
0
        }
94
0
    }
95
96
0
    _plugins_block = Block::create_unique();
97
0
    for (int i = 0; i < _s_tbls_columns.size(); ++i) {
98
0
        auto data_type =
99
0
                DataTypeFactory::instance().create_data_type(_s_tbls_columns[i].type, true);
100
0
        _plugins_block->insert(ColumnWithTypeAndName(data_type->create_column(), data_type,
101
0
                                                     _s_tbls_columns[i].name));
102
0
    }
103
0
    _plugins_block->reserve(_block_rows_limit);
104
105
0
    for (int i = 0; i < result_data.size(); i++) {
106
0
        const TRow& row = result_data[i];
107
0
        for (int j = 0; j < _s_tbls_columns.size(); j++) {
108
0
            const TCell& cell = row.column_value[j];
109
            // An unset string cell means SQL NULL (e.g. unknown PLUGIN_VERSION);
110
            // insert_block_column would materialize it as an empty string.
111
0
            if (!cell.__isset.stringVal) {
112
0
                MutableColumnPtr mutable_col_ptr =
113
0
                        IColumn::mutate(_plugins_block->get_by_position(j).column);
114
                // All _s_tbls_columns are declared nullable, so the column is
115
                // always a ColumnNullable wrapping the string column.
116
0
                assert_cast<ColumnNullable*>(mutable_col_ptr.get())->insert_data(nullptr, 0);
117
0
                _plugins_block->replace_by_position(j, std::move(mutable_col_ptr));
118
0
                continue;
119
0
            }
120
0
            RETURN_IF_ERROR(
121
0
                    insert_block_column(cell, j, _plugins_block.get(), _s_tbls_columns[j].type));
122
0
        }
123
0
    }
124
0
    return Status::OK();
125
0
}
126
127
0
Status SchemaPluginsScanner::get_next_block_internal(Block* block, bool* eos) {
128
0
    if (!_is_init) {
129
0
        return Status::InternalError("Used before initialized.");
130
0
    }
131
132
0
    if (nullptr == block || nullptr == eos) {
133
0
        return Status::InternalError("input pointer is nullptr.");
134
0
    }
135
136
0
    if (_plugins_block == nullptr) {
137
0
        RETURN_IF_ERROR(_get_plugins_block_from_fe());
138
0
        _total_rows = static_cast<int>(_plugins_block->rows());
139
0
    }
140
141
0
    if (_row_idx == _total_rows) {
142
0
        *eos = true;
143
0
        return Status::OK();
144
0
    }
145
146
0
    int current_batch_rows = std::min(_block_rows_limit, _total_rows - _row_idx);
147
0
    ScopedMutableBlock scoped_mblock(block);
148
0
    auto& mblock = scoped_mblock.mutable_block();
149
0
    RETURN_IF_ERROR(mblock.add_rows(_plugins_block.get(), _row_idx, current_batch_rows));
150
0
    _row_idx += current_batch_rows;
151
152
0
    *eos = _row_idx == _total_rows;
153
0
    return Status::OK();
154
0
}
155
156
} // namespace doris