ClickHouse

Форк
0
/
hasColumnInTable.cpp 
167 строк · 5.5 Кб
1
#include <Functions/IFunction.h>
2
#include <Functions/FunctionFactory.h>
3
#include <Functions/FunctionHelpers.h>
4
#include <Columns/ColumnString.h>
5
#include <Columns/ColumnConst.h>
6
#include <DataTypes/DataTypesNumber.h>
7
#include <Storages/IStorage.h>
8
#include <Interpreters/Cluster.h>
9
#include <Interpreters/Context.h>
10
#include <Interpreters/DatabaseCatalog.h>
11
#include <Storages/getStructureOfRemoteTable.h>
12

13

14
namespace DB
15
{
16
namespace ErrorCodes
17
{
18
    extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
19
    extern const int ILLEGAL_TYPE_OF_ARGUMENT;
20
    extern const int UNKNOWN_TABLE;
21
}
22

23
namespace
24
{
25

26
/** Usage:
27
 *  hasColumnInTable(['hostname'[, 'username'[, 'password']],] 'database', 'table', 'column')
28
 */
29
class FunctionHasColumnInTable : public IFunction, WithContext
30
{
31
public:
32
    static constexpr auto name = "hasColumnInTable";
33
    static FunctionPtr create(ContextPtr context_)
34
    {
35
        return std::make_shared<FunctionHasColumnInTable>(context_->getGlobalContext());
36
    }
37

38
    explicit FunctionHasColumnInTable(ContextPtr global_context_) : WithContext(global_context_)
39
    {
40
    }
41

42
    bool isVariadic() const override
43
    {
44
        return true;
45
    }
46
    size_t getNumberOfArguments() const override
47
    {
48
        return 0;
49
    }
50

51
    String getName() const override
52
    {
53
        return name;
54
    }
55

56
    DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override;
57

58
    bool isDeterministic() const override { return false; }
59

60
    bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
61

62
    ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const override;
63
};
64

65

66
DataTypePtr FunctionHasColumnInTable::getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const
67
{
68
    if (arguments.size() < 3 || arguments.size() > 6)
69
        throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Invalid number of arguments for function {}", getName());
70

71
    static const std::string arg_pos_description[] = {"First", "Second", "Third", "Fourth", "Fifth", "Sixth"};
72
    for (size_t i = 0; i < arguments.size(); ++i)
73
    {
74
        const ColumnWithTypeAndName & argument = arguments[i];
75

76
        if (!checkColumnConst<ColumnString>(argument.column.get()))
77
        {
78
            throw Exception(ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, "{} argument for function {} must be const String.",
79
                            arg_pos_description[i], getName());
80
        }
81
    }
82

83
    return std::make_shared<DataTypeUInt8>();
84
}
85

86

87
ColumnPtr FunctionHasColumnInTable::executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t input_rows_count) const
88
{
89
    auto get_string_from_columns = [&](const ColumnWithTypeAndName & column) -> String
90
    {
91
        const ColumnConst * const_column = checkAndGetColumnConst<ColumnString>(column.column.get());
92
        return const_column->getValue<String>();
93
    };
94

95
    size_t arg = 0;
96
    String host_name;
97
    String user_name;
98
    String password;
99

100
    if (arguments.size() > 3)
101
        host_name = get_string_from_columns(arguments[arg++]);
102

103
    if (arguments.size() > 4)
104
        user_name = get_string_from_columns(arguments[arg++]);
105

106
    if (arguments.size() > 5)
107
        password = get_string_from_columns(arguments[arg++]);
108

109
    String database_name = get_string_from_columns(arguments[arg++]);
110
    String table_name = get_string_from_columns(arguments[arg++]);
111
    String column_name = get_string_from_columns(arguments[arg++]);
112

113
    if (table_name.empty())
114
        throw Exception(ErrorCodes::UNKNOWN_TABLE, "Table name is empty");
115

116
    bool has_column;
117
    if (host_name.empty())
118
    {
119
        // FIXME this (probably) needs a non-constant access to query context,
120
        // because it might initialized a storage. Ideally, the tables required
121
        // by the query should be initialized at an earlier stage.
122
        const StoragePtr & table = DatabaseCatalog::instance().getTable(
123
            {database_name, table_name},
124
            const_pointer_cast<Context>(getContext()));
125
        auto table_metadata = table->getInMemoryMetadataPtr();
126
        has_column = table_metadata->getColumns().hasPhysical(column_name);
127
    }
128
    else
129
    {
130
        std::vector<std::vector<String>> host_names = {{ host_name }};
131

132
        bool treat_local_as_remote = false;
133
        bool treat_local_port_as_remote = getContext()->getApplicationType() == Context::ApplicationType::LOCAL;
134
        ClusterConnectionParameters params{
135
            !user_name.empty() ? user_name : "default",
136
            password,
137
            getContext()->getTCPPort(),
138
            treat_local_as_remote,
139
            treat_local_port_as_remote,
140
            /* secure= */ false,
141
            /* priority= */ Priority{1},
142
            /* cluster_name= */ "",
143
            /* password= */ ""
144
        };
145
        auto cluster = std::make_shared<Cluster>(getContext()->getSettings(), host_names, params);
146

147
        // FIXME this (probably) needs a non-constant access to query context,
148
        // because it might initialized a storage. Ideally, the tables required
149
        // by the query should be initialized at an earlier stage.
150
        auto remote_columns = getStructureOfRemoteTable(*cluster,
151
            {database_name, table_name},
152
            const_pointer_cast<Context>(getContext()));
153

154
        has_column = remote_columns.hasPhysical(column_name);
155
    }
156

157
    return DataTypeUInt8().createColumnConst(input_rows_count, Field{static_cast<UInt64>(has_column)});
158
}
159

160
}
161

162
REGISTER_FUNCTION(HasColumnInTable)
163
{
164
    factory.registerFunction<FunctionHasColumnInTable>();
165
}
166

167
}
168

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.