1#include <Databases/DatabaseDictionary.h>
2#include <Interpreters/Context.h>
3#include <Interpreters/ExternalDictionariesLoader.h>
4#include <Storages/StorageDictionary.h>
5#include <common/logger_useful.h>
6#include <IO/WriteBufferFromString.h>
7#include <IO/Operators.h>
8#include <Parsers/ParserCreateQuery.h>
9#include <Parsers/parseQuery.h>
10#include <Parsers/IAST.h>
11
12
13namespace DB
14{
15namespace ErrorCodes
16{
17 extern const int TABLE_ALREADY_EXISTS;
18 extern const int UNKNOWN_TABLE;
19 extern const int LOGICAL_ERROR;
20 extern const int CANNOT_GET_CREATE_TABLE_QUERY;
21 extern const int SYNTAX_ERROR;
22 extern const int UNSUPPORTED_METHOD;
23}
24
25DatabaseDictionary::DatabaseDictionary(const String & name_)
26 : IDatabase(name_),
27 log(&Logger::get("DatabaseDictionary(" + database_name + ")"))
28{
29}
30
31Tables DatabaseDictionary::listTables(const Context & context, const FilterByNameFunction & filter_by_name)
32{
33 Tables tables;
34 ExternalLoader::LoadResults load_results;
35 if (filter_by_name)
36 {
37 /// If `filter_by_name` is set, we iterate through all dictionaries with such names. That's why we need to load all of them.
38 load_results = context.getExternalDictionariesLoader().tryLoad<ExternalLoader::LoadResults>(filter_by_name);
39 }
40 else
41 {
42 /// If `filter_by_name` isn't set, we iterate through only already loaded dictionaries. We don't try to load all dictionaries in this case.
43 load_results = context.getExternalDictionariesLoader().getCurrentLoadResults();
44 }
45
46 for (const auto & load_result: load_results)
47 {
48 /// Load tables only from XML dictionaries, don't touch other
49 if (load_result.object && load_result.repository_name.empty())
50 {
51 auto dict_ptr = std::static_pointer_cast<const IDictionaryBase>(load_result.object);
52 auto dict_name = dict_ptr->getName();
53 const DictionaryStructure & dictionary_structure = dict_ptr->getStructure();
54 auto columns = StorageDictionary::getNamesAndTypes(dictionary_structure);
55 tables[dict_name] = StorageDictionary::create(getDatabaseName(), dict_name, ColumnsDescription{columns}, context, true, dict_name);
56 }
57 }
58 return tables;
59}
60
61bool DatabaseDictionary::isTableExist(
62 const Context & context,
63 const String & table_name) const
64{
65 return context.getExternalDictionariesLoader().getCurrentStatus(table_name) != ExternalLoader::Status::NOT_EXIST;
66}
67
68StoragePtr DatabaseDictionary::tryGetTable(
69 const Context & context,
70 const String & table_name) const
71{
72 auto dict_ptr = context.getExternalDictionariesLoader().tryGetDictionary(table_name);
73 if (dict_ptr)
74 {
75 const DictionaryStructure & dictionary_structure = dict_ptr->getStructure();
76 auto columns = StorageDictionary::getNamesAndTypes(dictionary_structure);
77 return StorageDictionary::create(getDatabaseName(), table_name, ColumnsDescription{columns}, context, true, table_name);
78 }
79
80 return {};
81}
82
83DatabaseTablesIteratorPtr DatabaseDictionary::getTablesIterator(const Context & context, const FilterByNameFunction & filter_by_name)
84{
85 return std::make_unique<DatabaseTablesSnapshotIterator>(listTables(context, filter_by_name));
86}
87
88bool DatabaseDictionary::empty(const Context & context) const
89{
90 return !context.getExternalDictionariesLoader().hasCurrentlyLoadedObjects();
91}
92
93ASTPtr DatabaseDictionary::getCreateTableQueryImpl(const Context & context,
94 const String & table_name, bool throw_on_error) const
95{
96 String query;
97 {
98 WriteBufferFromString buffer(query);
99
100 const auto & dictionaries = context.getExternalDictionariesLoader();
101 auto dictionary = throw_on_error ? dictionaries.getDictionary(table_name)
102 : dictionaries.tryGetDictionary(table_name);
103 if (!dictionary)
104 return {};
105
106 auto names_and_types = StorageDictionary::getNamesAndTypes(dictionary->getStructure());
107 buffer << "CREATE TABLE " << backQuoteIfNeed(database_name) << '.' << backQuoteIfNeed(table_name) << " (";
108 buffer << StorageDictionary::generateNamesAndTypesDescription(names_and_types.begin(), names_and_types.end());
109 buffer << ") Engine = Dictionary(" << backQuoteIfNeed(table_name) << ")";
110 }
111
112 ParserCreateQuery parser;
113 const char * pos = query.data();
114 std::string error_message;
115 auto ast = tryParseQuery(parser, pos, pos + query.size(), error_message,
116 /* hilite = */ false, "", /* allow_multi_statements = */ false, 0);
117
118 if (!ast && throw_on_error)
119 throw Exception(error_message, ErrorCodes::SYNTAX_ERROR);
120
121 return ast;
122}
123
124ASTPtr DatabaseDictionary::getCreateDatabaseQuery() const
125{
126 String query;
127 {
128 WriteBufferFromString buffer(query);
129 buffer << "CREATE DATABASE " << backQuoteIfNeed(database_name) << " ENGINE = Dictionary";
130 }
131 ParserCreateQuery parser;
132 return parseQuery(parser, query.data(), query.data() + query.size(), "", 0);
133}
134
135void DatabaseDictionary::shutdown()
136{
137}
138
139}
140