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 | |
21 | using namespace DB; |
22 | |
23 | static bool registered = false; |
24 | /// For debug |
25 | #pragma GCC diagnostic ignored "-Wunused-function" |
26 | static 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 | |
34 | TEST(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 | |
103 | TEST(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 | |
147 | TEST(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 | |
198 | TEST(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 | |