1#include <iostream>
2
3#include <sstream>
4#include <Core/Types.h>
5#include <Poco/Util/XMLConfiguration.h>
6#include <Parsers/ASTCreateQuery.h>
7#include <Parsers/ASTDropQuery.h>
8#include <Parsers/DumpASTNode.h>
9#include <Parsers/ParserCreateQuery.h>
10#include <Parsers/ParserDictionary.h>
11#include <Parsers/ParserDropQuery.h>
12#include <Parsers/ParserTablePropertiesQuery.h>
13#include <Parsers/TablePropertiesQueriesASTs.h>
14#include <Parsers/formatAST.h>
15#include <Parsers/parseQuery.h>
16#include <Dictionaries/getDictionaryConfigurationFromAST.h>
17#include <Dictionaries/registerDictionaries.h>
18
19#include <gtest/gtest.h>
20
21using namespace DB;
22
23static bool registered = false;
24/// For debug
25#pragma GCC diagnostic ignored "-Wunused-function"
26static std::string configurationToString(const DictionaryConfigurationPtr & config)
27{
28 const Poco::Util::XMLConfiguration * xml_config = dynamic_cast<const Poco::Util::XMLConfiguration *>(config.get());
29 std::ostringstream oss;
30 xml_config->save(oss);
31 return oss.str();
32}
33
34TEST(ConvertDictionaryAST, SimpleDictConfiguration)
35{
36 if (!registered)
37 {
38 registerDictionaries();
39 registered = true;
40 }
41
42 String input = " CREATE DICTIONARY test.dict1"
43 " ("
44 " key_column UInt64 DEFAULT 0,"
45 " second_column UInt8 DEFAULT 1,"
46 " third_column UInt8 DEFAULT 2"
47 " )"
48 " PRIMARY KEY key_column"
49 " SOURCE(CLICKHOUSE(HOST 'localhost' PORT 9000 USER 'default' PASSWORD '' DB 'test' TABLE 'table_for_dict'))"
50 " LAYOUT(FLAT())"
51 " LIFETIME(MIN 1 MAX 10)"
52 " RANGE(MIN second_column MAX third_column)";
53
54 ParserCreateDictionaryQuery parser;
55 ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "", 0);
56 ASTCreateQuery * create = ast->as<ASTCreateQuery>();
57 DictionaryConfigurationPtr config = getDictionaryConfigurationFromAST(*create);
58
59 /// name
60 EXPECT_EQ(config->getString("dictionary.database"), "test");
61 EXPECT_EQ(config->getString("dictionary.name"), "dict1");
62
63 /// lifetime
64 EXPECT_EQ(config->getInt("dictionary.lifetime.min"), 1);
65 EXPECT_EQ(config->getInt("dictionary.lifetime.max"), 10);
66
67 /// range
68 EXPECT_EQ(config->getString("dictionary.structure.range_min.name"), "second_column");
69 EXPECT_EQ(config->getString("dictionary.structure.range_max.name"), "third_column");
70 EXPECT_EQ(config->getString("dictionary.structure.range_min.type"), "UInt8");
71 EXPECT_EQ(config->getString("dictionary.structure.range_max.type"), "UInt8");
72
73
74 /// source
75 EXPECT_EQ(config->getString("dictionary.source.clickhouse.host"), "localhost");
76 EXPECT_EQ(config->getInt("dictionary.source.clickhouse.port"), 9000);
77 EXPECT_EQ(config->getString("dictionary.source.clickhouse.user"), "default");
78 EXPECT_EQ(config->getString("dictionary.source.clickhouse.password"), "");
79 EXPECT_EQ(config->getString("dictionary.source.clickhouse.db"), "test");
80 EXPECT_EQ(config->getString("dictionary.source.clickhouse.table"), "table_for_dict");
81
82 /// attributes and key
83 Poco::Util::AbstractConfiguration::Keys keys;
84 config->keys("dictionary.structure", keys);
85
86 EXPECT_EQ(keys.size(), 5); /// + ranged keys
87 EXPECT_EQ(config->getString("dictionary.structure." + keys[0] + ".name"), "second_column");
88 EXPECT_EQ(config->getString("dictionary.structure." + keys[0] + ".type"), "UInt8");
89 EXPECT_EQ(config->getInt("dictionary.structure." + keys[0] + ".null_value"), 1);
90
91 EXPECT_EQ(config->getString("dictionary.structure." + keys[1] + ".name"), "third_column");
92 EXPECT_EQ(config->getString("dictionary.structure." + keys[1] + ".type"), "UInt8");
93 EXPECT_EQ(config->getInt("dictionary.structure." + keys[1] + ".null_value"), 2);
94
95 EXPECT_EQ(keys[2], "id");
96 EXPECT_EQ(config->getString("dictionary.structure." + keys[2] + ".name"), "key_column");
97
98 /// layout
99 EXPECT_TRUE(config->has("dictionary.layout.flat"));
100}
101
102
103TEST(ConvertDictionaryAST, TrickyAttributes)
104{
105 if (!registered)
106 {
107 registerDictionaries();
108 registered = true;
109 }
110
111 String input = " CREATE DICTIONARY dict2"
112 " ("
113 " key_column UInt64 IS_OBJECT_ID,"
114 " second_column UInt8 HIERARCHICAL INJECTIVE,"
115 " third_column UInt8 DEFAULT 2 EXPRESSION rand() % 100 * 77"
116 " )"
117 " PRIMARY KEY key_column"
118 " LAYOUT(hashed())"
119 " LIFETIME(MIN 1 MAX 10)"
120 " SOURCE(CLICKHOUSE(HOST 'localhost'))";
121
122 ParserCreateDictionaryQuery parser;
123 ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "", 0);
124 ASTCreateQuery * create = ast->as<ASTCreateQuery>();
125 DictionaryConfigurationPtr config = getDictionaryConfigurationFromAST(*create);
126
127 Poco::Util::AbstractConfiguration::Keys keys;
128 config->keys("dictionary.structure", keys);
129
130 EXPECT_EQ(keys.size(), 3);
131 EXPECT_EQ(config->getString("dictionary.structure." + keys[0] + ".name"), "second_column");
132 EXPECT_EQ(config->getString("dictionary.structure." + keys[0] + ".type"), "UInt8");
133 EXPECT_EQ(config->getString("dictionary.structure." + keys[0] + ".null_value"), "");
134 EXPECT_EQ(config->getString("dictionary.structure." + keys[0] + ".hierarchical"), "true");
135 EXPECT_EQ(config->getString("dictionary.structure." + keys[0] + ".injective"), "true");
136
137 EXPECT_EQ(config->getString("dictionary.structure." + keys[1] + ".name"), "third_column");
138 EXPECT_EQ(config->getString("dictionary.structure." + keys[1] + ".type"), "UInt8");
139 EXPECT_EQ(config->getInt("dictionary.structure." + keys[1] + ".null_value"), 2);
140 EXPECT_EQ(config->getString("dictionary.structure." + keys[1] + ".expression"), "(rand() % 100) * 77");
141
142 EXPECT_EQ(keys[2], "id");
143 EXPECT_EQ(config->getString("dictionary.structure." + keys[2] + ".name"), "key_column");
144}
145
146
147TEST(ConvertDictionaryAST, ComplexKeyAndLayoutWithParams)
148{
149 if (!registered)
150 {
151 registerDictionaries();
152 registered = true;
153 }
154
155 String input = " CREATE DICTIONARY dict4"
156 " ("
157 " key_column1 String,"
158 " key_column2 UInt64,"
159 " third_column UInt8,"
160 " fourth_column UInt8"
161 " )"
162 " PRIMARY KEY key_column1, key_column2"
163 " SOURCE(MYSQL())"
164 " LAYOUT(COMPLEX_KEY_CACHE(size_in_cells 50))"
165 " LIFETIME(MIN 1 MAX 10)";
166
167 ParserCreateDictionaryQuery parser;
168 ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "", 0);
169 ASTCreateQuery * create = ast->as<ASTCreateQuery>();
170 DictionaryConfigurationPtr config = getDictionaryConfigurationFromAST(*create);
171
172 Poco::Util::AbstractConfiguration::Keys keys;
173 config->keys("dictionary.structure.key", keys);
174
175 EXPECT_EQ(keys.size(), 2);
176 EXPECT_EQ(config->getString("dictionary.structure.key." + keys[0] + ".name"), "key_column1");
177 EXPECT_EQ(config->getString("dictionary.structure.key." + keys[0] + ".type"), "String");
178
179 EXPECT_EQ(config->getString("dictionary.structure.key." + keys[1] + ".name"), "key_column2");
180 EXPECT_EQ(config->getString("dictionary.structure.key." + keys[1] + ".type"), "UInt64");
181
182 Poco::Util::AbstractConfiguration::Keys attrs;
183 config->keys("dictionary.structure", attrs);
184
185 EXPECT_EQ(attrs.size(), 3);
186 EXPECT_EQ(config->getString("dictionary.structure." + attrs[0] + ".name"), "third_column");
187 EXPECT_EQ(config->getString("dictionary.structure." + attrs[0] + ".type"), "UInt8");
188
189 EXPECT_EQ(config->getString("dictionary.structure." + attrs[1] + ".name"), "fourth_column");
190 EXPECT_EQ(config->getString("dictionary.structure." + attrs[1] + ".type"), "UInt8");
191
192 EXPECT_EQ(attrs[2], "key");
193
194 EXPECT_EQ(config->getInt("dictionary.layout.complex_key_cache.size_in_cells"), 50);
195}
196
197
198TEST(ConvertDictionaryAST, ComplexSource)
199{
200 if (!registered)
201 {
202 registerDictionaries();
203 registered = true;
204 }
205
206 String input = " CREATE DICTIONARY dict4"
207 " ("
208 " key_column UInt64,"
209 " second_column UInt8,"
210 " third_column UInt8"
211 " )"
212 " PRIMARY KEY key_column"
213 " SOURCE(MYSQL(HOST 'localhost' PORT 9000 USER 'default' REPLICA(HOST '127.0.0.1' PRIORITY 1) PASSWORD ''))"
214 " LAYOUT(CACHE(size_in_cells 50))"
215 " LIFETIME(MIN 1 MAX 10)"
216 " RANGE(MIN second_column MAX third_column)";
217
218 ParserCreateDictionaryQuery parser;
219 ASTPtr ast = parseQuery(parser, input.data(), input.data() + input.size(), "", 0);
220 ASTCreateQuery * create = ast->as<ASTCreateQuery>();
221 DictionaryConfigurationPtr config = getDictionaryConfigurationFromAST(*create);
222 /// source
223 EXPECT_EQ(config->getString("dictionary.source.mysql.host"), "localhost");
224 EXPECT_EQ(config->getInt("dictionary.source.mysql.port"), 9000);
225 EXPECT_EQ(config->getString("dictionary.source.mysql.user"), "default");
226 EXPECT_EQ(config->getString("dictionary.source.mysql.password"), "");
227 EXPECT_EQ(config->getString("dictionary.source.mysql.replica.host"), "127.0.0.1");
228 EXPECT_EQ(config->getInt("dictionary.source.mysql.replica.priority"), 1);
229}
230