aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Databases/DatabaseDictionary.cpp
blob: 04529ff5293ec761f14bad9e9a67ddab7a4f4eb8 (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <Databases/DatabaseDictionary.h>
#include <Interpreters/Context.h>
#include <Interpreters/ExternalDictionariesLoader.h>
#include <Dictionaries/DictionaryStructure.h>
#include <Storages/StorageDictionary.h>
#include <Common/logger_useful.h>
#include <IO/WriteBufferFromString.h>
#include <IO/Operators.h>
#include <Parsers/ParserCreateQuery.h>
#include <Parsers/parseQuery.h>
#include <Parsers/IAST.h>


namespace DB
{
namespace ErrorCodes
{
    extern const int SYNTAX_ERROR;
    extern const int CANNOT_GET_CREATE_DICTIONARY_QUERY;
}

namespace
{
    StoragePtr createStorageDictionary(const String & database_name, const ExternalLoader::LoadResult & load_result, ContextPtr context)
    {
        try
        {
            if (!load_result.config)
                return nullptr;

            DictionaryStructure dictionary_structure = ExternalDictionariesLoader::getDictionaryStructure(*load_result.config);
            auto comment = load_result.config->config->getString("dictionary.comment", "");

            return std::make_shared<StorageDictionary>(
                StorageID(database_name, load_result.name),
                load_result.name,
                dictionary_structure,
                comment,
                StorageDictionary::Location::DictionaryDatabase,
                context);
        }
        catch (Exception & e)
        {
            throw Exception(e.code(),
                "Error while loading dictionary '{}.{}': {}",
                    database_name, load_result.name, e.displayText());
        }
    }
}

DatabaseDictionary::DatabaseDictionary(const String & name_, ContextPtr context_)
    : IDatabase(name_), WithContext(context_->getGlobalContext())
    , log(&Poco::Logger::get("DatabaseDictionary(" + database_name + ")"))
{
}

Tables DatabaseDictionary::listTables(const FilterByNameFunction & filter_by_name) const
{
    Tables tables;
    auto load_results = getContext()->getExternalDictionariesLoader().getLoadResults(filter_by_name);
    String db_name = getDatabaseName();
    for (auto & load_result : load_results)
    {
        auto storage = createStorageDictionary(db_name, load_result, getContext());
        if (storage)
            tables.emplace(storage->getStorageID().table_name, storage);
    }
    return tables;
}

bool DatabaseDictionary::isTableExist(const String & table_name, ContextPtr) const
{
    return getContext()->getExternalDictionariesLoader().getCurrentStatus(table_name) != ExternalLoader::Status::NOT_EXIST;
}

StoragePtr DatabaseDictionary::tryGetTable(const String & table_name, ContextPtr) const
{
    auto load_result = getContext()->getExternalDictionariesLoader().getLoadResult(table_name);
    return createStorageDictionary(getDatabaseName(), load_result, getContext());
}

DatabaseTablesIteratorPtr DatabaseDictionary::getTablesIterator(ContextPtr, const FilterByNameFunction & filter_by_table_name) const
{
    return std::make_unique<DatabaseTablesSnapshotIterator>(listTables(filter_by_table_name), getDatabaseName());
}

bool DatabaseDictionary::empty() const
{
    return !getContext()->getExternalDictionariesLoader().hasObjects();
}

ASTPtr DatabaseDictionary::getCreateTableQueryImpl(const String & table_name, ContextPtr, bool throw_on_error) const
{
    String query;
    {
        WriteBufferFromString buffer(query);

        auto load_result = getContext()->getExternalDictionariesLoader().getLoadResult(table_name);
        if (!load_result.config)
        {
            if (throw_on_error)
                throw Exception(ErrorCodes::CANNOT_GET_CREATE_DICTIONARY_QUERY, "Dictionary {} doesn't exist", backQuote(table_name));
            return {};
        }

        auto names_and_types = StorageDictionary::getNamesAndTypes(ExternalDictionariesLoader::getDictionaryStructure(*load_result.config));
        buffer << "CREATE TABLE " << backQuoteIfNeed(getDatabaseName()) << '.' << backQuoteIfNeed(table_name) << " (";
        buffer << StorageDictionary::generateNamesAndTypesDescription(names_and_types);
        buffer << ") Engine = Dictionary(" << backQuoteIfNeed(table_name) << ")";
    }

    auto settings = getContext()->getSettingsRef();
    ParserCreateQuery parser;
    const char * pos = query.data();
    std::string error_message;
    auto ast = tryParseQuery(parser, pos, pos + query.size(), error_message,
            /* hilite = */ false, "", /* allow_multi_statements = */ false, 0, settings.max_parser_depth);

    if (!ast && throw_on_error)
        throw Exception::createDeprecated(error_message, ErrorCodes::SYNTAX_ERROR);

    return ast;
}

ASTPtr DatabaseDictionary::getCreateDatabaseQuery() const
{
    String query;
    {
        WriteBufferFromString buffer(query);
        buffer << "CREATE DATABASE " << backQuoteIfNeed(getDatabaseName()) << " ENGINE = Dictionary";
        if (const auto comment_value = getDatabaseComment(); !comment_value.empty())
            buffer << " COMMENT " << backQuote(comment_value);
    }
    auto settings = getContext()->getSettingsRef();
    ParserCreateQuery parser;
    return parseQuery(parser, query.data(), query.data() + query.size(), "", 0, settings.max_parser_depth);
}

void DatabaseDictionary::shutdown()
{
}

}