aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Dictionaries/DictionarySourceFactory.cpp
blob: c9f4bcb74461d9de576c0a2fb63f578d405b7bca (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "DictionarySourceFactory.h"

#include <Columns/ColumnsNumber.h>
#include <Core/Block.h>
#include <Core/ColumnWithTypeAndName.h>
#include <DataTypes/DataTypeNullable.h>
#include <DataTypes/DataTypesNumber.h>
#include <Poco/Logger.h>
#include <Common/logger_useful.h>
#include "DictionaryStructure.h"

namespace DB
{
namespace ErrorCodes
{
    extern const int UNKNOWN_ELEMENT_IN_CONFIG;
    extern const int EXCESSIVE_ELEMENT_IN_CONFIG;
    extern const int LOGICAL_ERROR;
}

namespace
{
    Block createSampleBlock(const DictionaryStructure & dict_struct)
    {
        Block block;

        if (dict_struct.id)
        {
            block.insert(ColumnWithTypeAndName{ColumnUInt64::create(1, 0), std::make_shared<DataTypeUInt64>(), dict_struct.id->name});
        }
        else if (dict_struct.key)
        {
            for (const auto & attribute : *dict_struct.key)
            {
                auto column = attribute.type->createColumn();
                column->insertDefault();

                block.insert(ColumnWithTypeAndName{std::move(column), attribute.type, attribute.name});
            }
        }

        if (dict_struct.range_min)
        {
            for (const auto & attribute : {dict_struct.range_min, dict_struct.range_max})
            {
                const auto & type = std::make_shared<DataTypeNullable>(attribute->type);
                auto column = type->createColumn();
                column->insertDefault();

                block.insert(ColumnWithTypeAndName{std::move(column), type, attribute->name});
            }
        }

        for (const auto & attribute : dict_struct.attributes)
        {
            auto column = attribute.type->createColumn();
            column->insert(attribute.null_value);

            block.insert(ColumnWithTypeAndName{std::move(column), attribute.type, attribute.name});
        }

        return block;
    }

}


DictionarySourceFactory::DictionarySourceFactory() : log(&Poco::Logger::get("DictionarySourceFactory"))
{
}

void DictionarySourceFactory::registerSource(const std::string & source_type, Creator create_source)
{
    if (!registered_sources.emplace(source_type, std::move(create_source)).second)
        throw Exception(ErrorCodes::LOGICAL_ERROR, "DictionarySourceFactory: the source name '{}' is not unique", source_type);
}

DictionarySourcePtr DictionarySourceFactory::create(
    const std::string & name,
    const Poco::Util::AbstractConfiguration & config,
    const std::string & config_prefix,
    const DictionaryStructure & dict_struct,
    ContextPtr global_context,
    const std::string & default_database,
    bool check_config) const
{
    Poco::Util::AbstractConfiguration::Keys keys;
    config.keys(config_prefix, keys);

    if (keys.empty() || keys.size() > 2)
        throw Exception(ErrorCodes::EXCESSIVE_ELEMENT_IN_CONFIG,
            "{}: element dictionary.source should have one or two child elements",
            name);

    const std::string & source_type = keys.front() == "settings" ? keys.back() : keys.front();

    const auto found = registered_sources.find(source_type);
    if (found != registered_sources.end())
    {
        const auto & create_source = found->second;
        auto sample_block = createSampleBlock(dict_struct);
        return create_source(dict_struct, config, config_prefix, sample_block, global_context, default_database, check_config);
    }

    throw Exception(ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG,
        "{}: unknown dictionary source type: {}",
        name,
        source_type);
}

DictionarySourceFactory & DictionarySourceFactory::instance()
{
    static DictionarySourceFactory instance;
    return instance;
}

}