1#include <sstream>
2#include <DataTypes/DataTypesNumber.h>
3#include <DataTypes/DataTypeDate.h>
4#include <Dictionaries/IDictionarySource.h>
5#include <Dictionaries/DictionaryStructure.h>
6#include <Storages/StorageDictionary.h>
7#include <Storages/StorageFactory.h>
8#include <Interpreters/Context.h>
9#include <Interpreters/evaluateConstantExpression.h>
10#include <Interpreters/ExternalDictionariesLoader.h>
11#include <Parsers/ASTLiteral.h>
12#include <common/logger_useful.h>
13#include <Common/typeid_cast.h>
14
15
16namespace DB
17{
18
19namespace ErrorCodes
20{
21 extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
22 extern const int THERE_IS_NO_COLUMN;
23}
24
25
26StorageDictionary::StorageDictionary(
27 const String & database_name_,
28 const String & table_name_,
29 const ColumnsDescription & columns_,
30 const Context & context,
31 bool attach,
32 const String & dictionary_name_)
33 : table_name(table_name_),
34 database_name(database_name_),
35 dictionary_name(dictionary_name_),
36 logger(&Poco::Logger::get("StorageDictionary"))
37{
38 setColumns(columns_);
39
40 if (!attach)
41 {
42 const auto & dictionary = context.getExternalDictionariesLoader().getDictionary(dictionary_name);
43 const DictionaryStructure & dictionary_structure = dictionary->getStructure();
44 checkNamesAndTypesCompatibleWithDictionary(dictionary_structure);
45 }
46}
47
48BlockInputStreams StorageDictionary::read(
49 const Names & column_names,
50 const SelectQueryInfo & /*query_info*/,
51 const Context & context,
52 QueryProcessingStage::Enum /*processed_stage*/,
53 const size_t max_block_size,
54 const unsigned /*threads*/)
55{
56 auto dictionary = context.getExternalDictionariesLoader().getDictionary(dictionary_name);
57 return BlockInputStreams{dictionary->getBlockInputStream(column_names, max_block_size)};
58}
59
60NamesAndTypesList StorageDictionary::getNamesAndTypes(const DictionaryStructure & dictionary_structure)
61{
62 NamesAndTypesList dictionary_names_and_types;
63
64 if (dictionary_structure.id)
65 dictionary_names_and_types.emplace_back(dictionary_structure.id->name, std::make_shared<DataTypeUInt64>());
66 if (dictionary_structure.range_min)
67 dictionary_names_and_types.emplace_back(dictionary_structure.range_min->name, dictionary_structure.range_min->type);
68 if (dictionary_structure.range_max)
69 dictionary_names_and_types.emplace_back(dictionary_structure.range_max->name, dictionary_structure.range_max->type);
70 if (dictionary_structure.key)
71 for (const auto & attribute : *dictionary_structure.key)
72 dictionary_names_and_types.emplace_back(attribute.name, attribute.type);
73
74 for (const auto & attribute : dictionary_structure.attributes)
75 dictionary_names_and_types.emplace_back(attribute.name, attribute.type);
76
77 return dictionary_names_and_types;
78}
79
80void StorageDictionary::checkNamesAndTypesCompatibleWithDictionary(const DictionaryStructure & dictionary_structure) const
81{
82 auto dictionary_names_and_types = getNamesAndTypes(dictionary_structure);
83 std::set<NameAndTypePair> names_and_types_set(dictionary_names_and_types.begin(), dictionary_names_and_types.end());
84
85 for (const auto & column : getColumns().getOrdinary())
86 {
87 if (names_and_types_set.find(column) == names_and_types_set.end())
88 {
89 std::string message = "Not found column ";
90 message += column.name + " " + column.type->getName();
91 message += " in dictionary " + dictionary_name + ". ";
92 message += "There are only columns ";
93 message += generateNamesAndTypesDescription(dictionary_names_and_types.begin(), dictionary_names_and_types.end());
94 throw Exception(message, ErrorCodes::THERE_IS_NO_COLUMN);
95 }
96 }
97}
98
99void registerStorageDictionary(StorageFactory & factory)
100{
101 factory.registerStorage("Dictionary", [](const StorageFactory::Arguments & args)
102 {
103 if (args.engine_args.size() != 1)
104 throw Exception("Storage Dictionary requires single parameter: name of dictionary",
105 ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
106
107 args.engine_args[0] = evaluateConstantExpressionOrIdentifierAsLiteral(args.engine_args[0], args.local_context);
108 String dictionary_name = args.engine_args[0]->as<ASTLiteral &>().value.safeGet<String>();
109
110 return StorageDictionary::create(
111 args.database_name, args.table_name, args.columns, args.context, args.attach, dictionary_name);
112 });
113}
114
115}
116