/Users/deen/code/yugabyte-db/src/yb/yql/cql/ql/test/ql-query-test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | //-------------------------------------------------------------------------------------------------- |
2 | | // Copyright (c) YugaByte, Inc. |
3 | | // |
4 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
5 | | // in compliance with the License. You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
10 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
11 | | // or implied. See the License for the specific language governing permissions and limitations |
12 | | // under the License. |
13 | | // |
14 | | //-------------------------------------------------------------------------------------------------- |
15 | | |
16 | | #include <cmath> |
17 | | #include <thread> |
18 | | |
19 | | #include "yb/client/client.h" |
20 | | #include "yb/client/table.h" |
21 | | |
22 | | #include "yb/common/jsonb.h" |
23 | | #include "yb/common/partition.h" |
24 | | #include "yb/common/ql_protocol_util.h" |
25 | | #include "yb/common/ql_type.h" |
26 | | #include "yb/common/ql_value.h" |
27 | | |
28 | | #include "yb/gutil/strings/substitute.h" |
29 | | |
30 | | #include "yb/master/master.h" |
31 | | #include "yb/master/ts_manager.h" |
32 | | |
33 | | #include "yb/util/decimal.h" |
34 | | #include "yb/util/result.h" |
35 | | #include "yb/util/status_log.h" |
36 | | #include "yb/util/yb_partition.h" |
37 | | |
38 | | #include "yb/yql/cql/ql/test/ql-test-base.h" |
39 | | |
40 | | using std::string; |
41 | | using std::unique_ptr; |
42 | | using std::shared_ptr; |
43 | | using strings::Substitute; |
44 | | |
45 | | namespace yb { |
46 | | namespace ql { |
47 | | |
48 | | class TestQLQuery : public QLTestBase { |
49 | | public: |
50 | 0 | TestQLQuery() : QLTestBase() { |
51 | 0 | } |
52 | | |
53 | | std::shared_ptr<QLRowBlock> ExecSelect(TestQLProcessor *processor, int expected_rows = 1) { |
54 | | auto select = "SELECT c1, c2, c3 FROM test_table WHERE c1 = 1"; |
55 | | Status s = processor->Run(select); |
56 | | CHECK(s.ok()); |
57 | | auto row_block = processor->row_block(); |
58 | | EXPECT_EQ(expected_rows, row_block->row_count()); |
59 | | return row_block; |
60 | | } |
61 | | |
62 | 0 | void VerifyExpiry(TestQLProcessor *processor) { |
63 | 0 | ExecSelect(processor, 0); |
64 | 0 | } |
65 | | |
66 | 0 | void CreateTableAndInsertRow(TestQLProcessor *processor, bool with_ttl = true) { |
67 | | // Create the table. |
68 | 0 | const char *create_stmt = |
69 | 0 | "CREATE TABLE test_table(c1 int, c2 int, c3 int, " |
70 | 0 | "primary key(c1));"; |
71 | 0 | Status s = processor->Run(create_stmt); |
72 | 0 | CHECK(s.ok()); |
73 | |
|
74 | 0 | std::string insert_stmt("INSERT INTO test_table(c1, c2, c3) VALUES(1, 2, 3)"); |
75 | 0 | if (with_ttl) { |
76 | | // Insert row with ttl. |
77 | 0 | insert_stmt += " USING TTL 1;"; |
78 | 0 | } else { |
79 | 0 | insert_stmt += ";"; |
80 | 0 | } |
81 | 0 | s = processor->Run(insert_stmt); |
82 | 0 | CHECK_OK(s); |
83 | | |
84 | | // Verify row is present. |
85 | 0 | auto row_block = ExecSelect(processor); |
86 | 0 | QLRow& row = row_block->row(0); |
87 | |
|
88 | 0 | EXPECT_EQ(1, row.column(0).int32_value()); |
89 | 0 | EXPECT_EQ(2, row.column(1).int32_value()); |
90 | 0 | EXPECT_EQ(3, row.column(2).int32_value()); |
91 | 0 | } |
92 | | |
93 | | void TestSelectWithBounds( |
94 | | string select_stmt, |
95 | | TestQLProcessor* processor, |
96 | | const std::vector<std::tuple<int64_t, int, string, int, int>>& rows, |
97 | 0 | int start_idx, int end_idx, string order_by_clause) { |
98 | 0 | std::vector<std::tuple<int64_t, int, string, int, int>> test_rows( |
99 | 0 | &rows[start_idx], &rows[end_idx]); |
100 | |
|
101 | 0 | select_stmt += order_by_clause; |
102 | |
|
103 | 0 | if (order_by_clause == " ORDER BY r1 DESC") { |
104 | 0 | std::reverse(test_rows.begin(), test_rows.end()); |
105 | 0 | } |
106 | 0 | CHECK_OK(processor->Run(select_stmt)); |
107 | 0 | auto row_block = processor->row_block(); |
108 | | // checking result |
109 | 0 | ASSERT_EQ(test_rows.size(), row_block->row_count()); |
110 | 0 | for (size_t i = 0; i < test_rows.size(); i++) { |
111 | 0 | QLRow &row = row_block->row(i); |
112 | 0 | EXPECT_EQ(std::get<1>(test_rows[i]), row.column(0).int32_value()); |
113 | 0 | EXPECT_EQ(std::get<2>(test_rows[i]), row.column(1).string_value()); |
114 | 0 | EXPECT_EQ(std::get<3>(test_rows[i]), row.column(2).int32_value()); |
115 | 0 | EXPECT_EQ(std::get<4>(test_rows[i]), row.column(3).int32_value()); |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | | // Make sure regular scan works, but errors when order by is present. |
120 | | void TestSelectWithoutOrderBy( |
121 | | string select_stmt, |
122 | | TestQLProcessor *processor, |
123 | | const std::vector<std::tuple<int64_t, int, string, int, int>> &rows, |
124 | 0 | int start_idx, int end_idx) { |
125 | | // Forward scan |
126 | 0 | TestSelectWithBounds(select_stmt, processor, rows, start_idx, end_idx, ""); |
127 | 0 | CHECK_INVALID_STMT(select_stmt + " ORDER BY r1 DESC"); |
128 | 0 | CHECK_INVALID_STMT(select_stmt + " ORDER BY r1 ASC"); |
129 | 0 | } |
130 | | |
131 | | // Make sure normal scans and those with order by clause all work. |
132 | | void TestSelectWithOrderBy( |
133 | | string select_stmt, |
134 | | TestQLProcessor *processor, |
135 | | const std::vector<std::tuple<int64_t, int, string, int, int>> &rows, |
136 | 0 | int start_idx, int end_idx) { |
137 | | // Forward scan |
138 | 0 | TestSelectWithBounds(select_stmt, processor, rows, start_idx, end_idx, ""); |
139 | 0 | TestSelectWithBounds(select_stmt, processor, rows, start_idx, end_idx, " ORDER BY r1 ASC"); |
140 | 0 | TestSelectWithBounds(select_stmt, processor, rows, start_idx, end_idx, " ORDER BY r1 DESC"); |
141 | 0 | } |
142 | | |
143 | | void TestScanWithBoundsPartitionOps(const std::string& func_name, int64_t max_hash, |
144 | 0 | int64_t min_hash) { |
145 | | //---------------------------------------------------------------------------------------------- |
146 | | // Setting up cluster |
147 | | //---------------------------------------------------------------------------------------------- |
148 | | |
149 | | // Init the simulated cluster. |
150 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
151 | | |
152 | | // Get a processor. |
153 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
154 | | |
155 | | // Create test table. |
156 | 0 | CHECK_OK(processor->Run("CREATE TABLE scan_bounds_test (h1 int, h2 text, r1 int, v1 int," |
157 | 0 | " PRIMARY KEY((h1, h2), r1));")); |
158 | |
|
159 | 0 | client::YBTableName name(YQL_DATABASE_CQL, kDefaultKeyspaceName, "scan_bounds_test"); |
160 | 0 | shared_ptr<client::YBTable> table; |
161 | |
|
162 | 0 | ASSERT_OK(client_->OpenTable(name, &table)); |
163 | | |
164 | | //---------------------------------------------------------------------------------------------- |
165 | | // Initializing rows data |
166 | | //---------------------------------------------------------------------------------------------- |
167 | | |
168 | | // generating input data with hash_code and inserting into table |
169 | 0 | std::vector<std::tuple<int64_t, int, string, int, int>> rows; |
170 | 0 | for (int i = 0; i < 10; i++) { |
171 | 0 | std::string i_str = std::to_string(i); |
172 | 0 | google::protobuf::RepeatedPtrField<QLExpressionPB> row; |
173 | 0 | row.Add()->mutable_value()->set_int32_value(i); |
174 | 0 | row.Add()->mutable_value()->set_string_value(i_str); |
175 | |
|
176 | 0 | std::string part_key; |
177 | 0 | CHECK_OK(table->partition_schema().EncodeKey(row, &part_key)); |
178 | 0 | uint16_t hash_code = PartitionSchema::DecodeMultiColumnHashValue(part_key); |
179 | |
|
180 | 0 | int64_t cql_hash = func_name == "token" ? YBPartition::YBToCqlHashCode(hash_code) : hash_code; |
181 | 0 | std::tuple<int64_t, int, string, int, int> values(cql_hash, i, i_str, i, i); |
182 | 0 | rows.push_back(values); |
183 | 0 | string stmt = Substitute("INSERT INTO scan_bounds_test (h1, h2, r1, v1) VALUES " |
184 | 0 | "($0, '$1', $2, $3);", i, i, i, i); |
185 | 0 | CHECK_OK(processor->Run(stmt)); |
186 | 0 | } |
187 | | |
188 | | // ordering rows by hash code |
189 | 0 | std::sort(rows.begin(), rows.end(), |
190 | 0 | [](const std::tuple<int64_t, int, string, int, int>& r1, |
191 | 0 | const std::tuple<int64_t, int, string, int, int>& r2) -> bool { |
192 | 0 | return std::get<0>(r1) < std::get<0>(r2); |
193 | 0 | }); |
194 | | |
195 | | // CQL uses 64 bit hashes, but YB uses 16-bit internally. |
196 | | // Our bucket range is [cql_hash, cql_hash + bucket_size) -- start-inclusive, end-exclusive |
197 | | // We test the bucket ranges below by choosing the appropriate values for the bounds. |
198 | 0 | int64_t bucket_size = 1; |
199 | 0 | if (func_name == "token") { |
200 | 0 | bucket_size = bucket_size << 48; |
201 | 0 | } |
202 | | |
203 | | //---------------------------------------------------------------------------------------------- |
204 | | // Testing Select with lower bound |
205 | | //---------------------------------------------------------------------------------------------- |
206 | | |
207 | | //---------------------------------- Exclusive Lower Bound ------------------------------------- |
208 | 0 | string select_stmt_template = "SELECT * FROM scan_bounds_test WHERE $0(h1, h2) > $1"; |
209 | | |
210 | | // Entire range: hashes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 |
211 | 0 | TestSelectWithoutOrderBy( |
212 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[0]) - 1), processor, rows, |
213 | 0 | 0, 10); |
214 | | // Partial range: hashes 4, 5, 6, 7, 8, 9 |
215 | 0 | TestSelectWithoutOrderBy( |
216 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[3])), processor, rows, |
217 | 0 | 4, 10); |
218 | | // Empty range: no hashes. |
219 | 0 | TestSelectWithoutOrderBy( |
220 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[9])), processor, rows, |
221 | 0 | 0, 0); |
222 | | // Empty range: no hashes (checking overflow for max Cql hash) |
223 | 0 | TestSelectWithoutOrderBy( |
224 | 0 | Substitute(select_stmt_template, func_name, max_hash), processor, rows, |
225 | 0 | 0, 0); |
226 | | |
227 | | //---------------------------------- Inclusive Lower Bound ------------------------------------- |
228 | 0 | select_stmt_template = "SELECT * FROM scan_bounds_test WHERE $0(h1, h2) >= $1"; |
229 | | // Entire range: hashes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. |
230 | 0 | TestSelectWithoutOrderBy( |
231 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[0]) + bucket_size - 1), |
232 | 0 | processor, rows, 0, 10); |
233 | | // Partial range: hashes 6, 7, 8, 9 |
234 | 0 | TestSelectWithoutOrderBy( |
235 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[6]) + bucket_size - 1), |
236 | 0 | processor, rows, 6, 10); |
237 | | // Empty range: no hashes |
238 | 0 | TestSelectWithoutOrderBy( |
239 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[9]) + bucket_size), processor, |
240 | 0 | rows, 0, 0); |
241 | | |
242 | | //---------------------------------------------------------------------------------------------- |
243 | | // Testing Select with upper bound |
244 | | //---------------------------------------------------------------------------------------------- |
245 | | |
246 | | //---------------------------------- Exclusive Upper Bound ------------------------------------- |
247 | 0 | select_stmt_template = "SELECT * FROM scan_bounds_test WHERE $0(h1, h2) < $1"; |
248 | | // Entire range: hashes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 |
249 | 0 | TestSelectWithoutOrderBy( |
250 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[9]) + bucket_size), processor, |
251 | 0 | rows, 0, 10); |
252 | | // Partial range: hashes 0, 1, 2, 3, 4, 5, 6 |
253 | 0 | TestSelectWithoutOrderBy( |
254 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[7]) + bucket_size - 1), |
255 | 0 | processor, rows, 0, 7); |
256 | | // Empty range: no hashes |
257 | 0 | TestSelectWithoutOrderBy( |
258 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[0]) + bucket_size - 1), |
259 | 0 | processor, rows, 0, 0); |
260 | | |
261 | | //---------------------------------- Inclusive Upper Bound ------------------------------------- |
262 | 0 | select_stmt_template = "SELECT * FROM scan_bounds_test WHERE $0(h1, h2) <= $1"; |
263 | | // Entire range: hashes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 |
264 | 0 | TestSelectWithoutOrderBy( |
265 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[9])), processor, rows, 0, 10); |
266 | | // Partial range: hashes 0, 1, 2 |
267 | 0 | TestSelectWithoutOrderBy( |
268 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[2])), processor, rows, 0, 3); |
269 | | // Empty range: no hashes |
270 | 0 | TestSelectWithoutOrderBy( |
271 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[0]) - 1), processor, rows, 0, |
272 | 0 | 0); |
273 | | |
274 | | //---------------------------------------------------------------------------------------------- |
275 | | // Testing Select with both lower and upper bounds |
276 | | //---------------------------------------------------------------------------------------------- |
277 | 0 | select_stmt_template = "SELECT * FROM scan_bounds_test WHERE $0(h1, h2) $1 $2 AND $3(h1, h2) " |
278 | 0 | "$4 $5"; |
279 | | // Entire range: hashes 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 |
280 | 0 | TestSelectWithoutOrderBy( |
281 | 0 | Substitute(select_stmt_template, func_name, ">=", std::get<0>(rows[0]) + bucket_size - 1, |
282 | 0 | func_name, "<=", std::get<0>(rows[9])), processor, rows, 0, 10); |
283 | | // Partial Range: hashes 2, 3, 4, 5, 6, 7, 8 |
284 | 0 | TestSelectWithoutOrderBy( |
285 | 0 | Substitute(select_stmt_template, func_name, ">", std::get<0>(rows[1]), |
286 | 0 | func_name, "<=", std::get<0>(rows[8])), processor, rows, 2, 9); |
287 | | // Partial Range: hashes 4, 5, 6 |
288 | 0 | TestSelectWithoutOrderBy( |
289 | 0 | Substitute(select_stmt_template, func_name, ">=", std::get<0>(rows[4]) + bucket_size - 1, |
290 | 0 | func_name, "<", std::get<0>(rows[7]) + bucket_size - 1), processor, rows, |
291 | 0 | 4, 7); |
292 | | // Empty Range (inclusive lower bound): no hashes |
293 | 0 | TestSelectWithoutOrderBy( |
294 | 0 | Substitute(select_stmt_template, func_name, ">=", std::get<0>(rows[2]) + bucket_size - 1, |
295 | 0 | func_name, "<", std::get<0>(rows[2]) + bucket_size - 1), processor, rows, 0, 0); |
296 | | // Empty Range (inclusive upper bound): no hashes |
297 | 0 | TestSelectWithoutOrderBy( |
298 | 0 | Substitute(select_stmt_template, func_name, ">", std::get<0>(rows[2]), |
299 | 0 | func_name, "<=", std::get<0>(rows[2])), processor, rows, 0, 0); |
300 | | // Empty range: no hashes (checking overflow for max Cql hash) |
301 | 0 | TestSelectWithoutOrderBy( |
302 | 0 | Substitute(select_stmt_template, func_name, "<=", std::get<0>(rows[9]), func_name, ">", |
303 | 0 | max_hash), processor, rows, 0, 0); |
304 | | |
305 | | //---------------------------------------------------------------------------------------------- |
306 | | // Testing Select with range limits |
307 | | //---------------------------------------------------------------------------------------------- |
308 | | // Entire range: [min, max]. |
309 | 0 | TestSelectWithoutOrderBy( |
310 | 0 | Substitute(select_stmt_template, func_name, ">=", min_hash, func_name, "<=", max_hash), |
311 | 0 | processor, rows, 0, 10); |
312 | | |
313 | | // Entire range: [min, min] (upper bound min is treated as a special case in Cassandra). |
314 | 0 | TestSelectWithoutOrderBy( |
315 | 0 | Substitute(select_stmt_template, func_name, ">=", min_hash, func_name, "<=", min_hash), |
316 | 0 | processor, rows, 0, func_name == "token" ? 10 : 0); |
317 | | |
318 | | // Entire range: [min, min). (upper bound min is treated as a special case in Cassandra). |
319 | 0 | TestSelectWithoutOrderBy( |
320 | 0 | Substitute(select_stmt_template, func_name, ">=", min_hash, func_name, "<", min_hash), |
321 | 0 | processor, rows, 0, func_name == "token" ? 10 : 0); |
322 | | |
323 | | // Empty range: (max, max]. |
324 | 0 | TestSelectWithoutOrderBy( |
325 | 0 | Substitute(select_stmt_template, func_name, ">", max_hash, func_name, "<=", max_hash), |
326 | 0 | processor, rows, 0, 0); |
327 | | |
328 | | // Empty range: (max, min] (max as strict lower bound already excludes all hashes). |
329 | 0 | TestSelectWithoutOrderBy( |
330 | 0 | Substitute(select_stmt_template, func_name, ">", max_hash, func_name, "<=", min_hash), |
331 | 0 | processor, rows, 0, 0); |
332 | | |
333 | | //---------------------------------------------------------------------------------------------- |
334 | | // Testing Select with exact partition key |
335 | | //---------------------------------------------------------------------------------------------- |
336 | 0 | select_stmt_template = "SELECT * FROM scan_bounds_test WHERE $0(h1, h2) = $1"; |
337 | | // testing existing hash: 2 |
338 | 0 | TestSelectWithoutOrderBy( |
339 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[2])), processor, rows, |
340 | 0 | 2, 3); |
341 | 0 | TestSelectWithoutOrderBy( |
342 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[2])), processor, rows, |
343 | 0 | 2, 3); |
344 | | // testing non-existing hash: empty |
345 | 0 | TestSelectWithoutOrderBy( |
346 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[9]) + bucket_size), processor, |
347 | 0 | rows, 0, 0); |
348 | 0 | TestSelectWithoutOrderBy( |
349 | 0 | Substitute(select_stmt_template, func_name, std::get<0>(rows[9]) + bucket_size), processor, |
350 | 0 | rows, 0, 0); |
351 | | |
352 | | //---------------------------------------------------------------------------------------------- |
353 | | // Testing Select with conditions on both partition key and individual hash columns |
354 | | // - These queries are not always logical (i.e. partition key condition is usually irrelevant |
355 | | // - if part. column values are given) but Cassandra supports them so we replicate its |
356 | | // behavior |
357 | | //---------------------------------------------------------------------------------------------- |
358 | 0 | select_stmt_template = "SELECT * FROM scan_bounds_test WHERE " |
359 | 0 | "h1 = $0 AND h2 = '$1' AND $2(h1, h2) $3 $4"; |
360 | | |
361 | | // checking existing row with exact partition key: 6 |
362 | 0 | TestSelectWithOrderBy( |
363 | 0 | Substitute(select_stmt_template, std::get<1>(rows[6]), std::get<2>(rows[6]), func_name, |
364 | 0 | "=", std::get<0>(rows[6])), processor, rows, 6, 7); |
365 | | // checking existing row with partition key bound: 3 with partition upper bound 7 (to include 3) |
366 | 0 | TestSelectWithOrderBy( |
367 | 0 | Substitute(select_stmt_template, std::get<1>(rows[3]), std::get<2>(rows[3]), func_name, |
368 | 0 | "<=", std::get<0>(rows[7])), processor, rows, 3, 4); |
369 | | // checking existing row with partition key bound: 4 with partition lower bound 5 (to exclude 4) |
370 | 0 | TestSelectWithOrderBy( |
371 | 0 | Substitute(select_stmt_template, std::get<1>(rows[4]), std::get<2>(rows[4]), func_name, |
372 | 0 | ">=", std::get<0>(rows[5])), processor, rows, 0, 0); |
373 | | // checking existing row with partition key bound: 7 with partition upper bound 6 (to exclude 7) |
374 | 0 | TestSelectWithOrderBy( |
375 | 0 | Substitute(select_stmt_template, std::get<1>(rows[7]), std::get<2>(rows[7]), func_name, |
376 | 0 | "<=", std::get<0>(rows[6])), processor, rows, 0, 0); |
377 | | |
378 | | //---------------------------------------------------------------------------------------------- |
379 | | // Testing Invalid Statements |
380 | | //---------------------------------------------------------------------------------------------- |
381 | | |
382 | | // Invalid number of arguments. |
383 | 0 | CHECK_INVALID_STMT(Substitute("SELECT * FROM scan_bounds_test WHERE $0() > 0", func_name)); |
384 | 0 | CHECK_INVALID_STMT(Substitute("SELECT * FROM scan_bounds_test WHERE $0(h1) > 0", func_name)); |
385 | 0 | CHECK_INVALID_STMT(Substitute("SELECT * FROM scan_bounds_test WHERE $0(h1,h2,h1) > 0", |
386 | 0 | func_name)); |
387 | | |
388 | | // Invalid argument values. |
389 | 0 | CHECK_INVALID_STMT(Substitute("SELECT * FROM scan_bounds_test WHERE $0(h2,h1) > 0", func_name)); |
390 | 0 | CHECK_INVALID_STMT(Substitute("SELECT * FROM scan_bounds_test WHERE $0(h1,h1) > 0", func_name)); |
391 | 0 | CHECK_INVALID_STMT(Substitute("SELECT * FROM scan_bounds_test WHERE $0(h2,h2) > 0", func_name)); |
392 | 0 | CHECK_INVALID_STMT(Substitute("SELECT * FROM scan_bounds_test WHERE $0(r1,h2) > 0", func_name)); |
393 | 0 | CHECK_INVALID_STMT(Substitute("SELECT * FROM scan_bounds_test WHERE $0(r1,v1) > 0", func_name)); |
394 | | |
395 | | // Illogical conditions. |
396 | | // Two "greater-than" bounds |
397 | 0 | CHECK_INVALID_STMT( |
398 | 0 | Substitute("SELECT * FROM scan_bounds_test WHERE $0(h1,h2) > 0 AND $1(h1,h2) >= 0", |
399 | 0 | func_name, func_name)); |
400 | | // Two "less-than" bounds |
401 | 0 | CHECK_INVALID_STMT( |
402 | 0 | Substitute("SELECT * FROM scan_bounds_test WHERE $0(h1,h2) <= 0 AND $1(h1,h2) < 0", |
403 | 0 | func_name, func_name)); |
404 | | // Two "equal" conditions |
405 | 0 | CHECK_INVALID_STMT( |
406 | 0 | Substitute("SELECT * FROM scan_bounds_test WHERE $0(h1,h2) = 0 AND $1(h1,h2) = 0", |
407 | 0 | func_name, func_name)); |
408 | | // Both "equal" and "less than" conditions |
409 | 0 | CHECK_INVALID_STMT( |
410 | 0 | Substitute("SELECT * FROM scan_bounds_test WHERE $0(h1,h2) = 0 AND $1(h1,h2) <= 0", |
411 | 0 | func_name, func_name)); |
412 | | // Both "equal" and "greater than" conditions |
413 | 0 | CHECK_INVALID_STMT( |
414 | 0 | Substitute("SELECT * FROM scan_bounds_test WHERE $0(h1,h2) = 0 AND $1(h1,h2) >= 0", |
415 | 0 | func_name, func_name)); |
416 | 0 | } |
417 | | |
418 | 0 | void TestPartitionHash(const std::string& func_name) { |
419 | | //---------------------------------------------------------------------------------------------- |
420 | | // Setting up cluster |
421 | | //---------------------------------------------------------------------------------------------- |
422 | | |
423 | | // Init the simulated cluster. |
424 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
425 | | |
426 | | // Get a processor. |
427 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
428 | | |
429 | | //---------------------------------------------------------------------------------------------- |
430 | | // Testing all simple types (that are allowed in primary keys) |
431 | | //---------------------------------------------------------------------------------------------- |
432 | 0 | CHECK_OK(processor->Run( |
433 | 0 | "create table partition_hash_bcall_simple_test(" |
434 | 0 | " h1 tinyint, h2 smallint, h3 int, h4 bigint, h5 varchar, h6 blob, h7 timestamp, " |
435 | 0 | " h8 decimal, h9 inet, h10 uuid, h11 timeuuid, r int, v int," |
436 | 0 | " primary key((h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11), r));")); |
437 | | |
438 | | // Sample values to check hash value computation |
439 | 0 | string key_values = "99, 9999, 999999, 99999999, 'foo bar', 0x12fe9a, " |
440 | 0 | "'1999-12-01 16:32:44 GMT', 987654.0123, '204.101.0.168', " |
441 | 0 | "97bda55b-6175-4c39-9e04-7c0205c709dc, 97bda55b-6175-1c39-9e04-7c0205c709dc"; |
442 | |
|
443 | 0 | string insert_stmt = "INSERT INTO partition_hash_bcall_simple_test (h1, h2, h3, h4, h5, h6, " |
444 | 0 | "h7, h8, h9, h10, h11, r, v) VALUES ($0, 1, 1);"; |
445 | |
|
446 | 0 | CHECK_OK(processor->Run(Substitute(insert_stmt, key_values))); |
447 | |
|
448 | 0 | string select_stmt = Substitute( |
449 | 0 | "SELECT * FROM partition_hash_bcall_simple_test WHERE " |
450 | 0 | "$0(h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11) = $1($2)", func_name, |
451 | 0 | func_name, key_values); |
452 | |
|
453 | 0 | CHECK_OK(processor->Run(select_stmt)); |
454 | 0 | auto row_block = processor->row_block(); |
455 | | |
456 | | // Checking result. |
457 | 0 | ASSERT_EQ(1, row_block->row_count()); |
458 | | |
459 | | //---------------------------------------------------------------------------------------------- |
460 | | // Testing separate UDT type. |
461 | | //---------------------------------------------------------------------------------------------- |
462 | 0 | CHECK_OK(processor->Run("CREATE TYPE udt_partition_hash_test(a int, b text)")); |
463 | |
|
464 | 0 | CHECK_OK(processor->Run( |
465 | 0 | "CREATE TABLE partition_hash_bcall_udt_test(" |
466 | 0 | " h frozen<udt_partition_hash_test>, r int, v int, PRIMARY KEY ((h), r))")); |
467 | | |
468 | | // Sample values to check hash value computation |
469 | 0 | key_values = "{a : 1, b : 'foo'}"; |
470 | |
|
471 | 0 | insert_stmt = Substitute("INSERT INTO partition_hash_bcall_udt_test " |
472 | 0 | "(h, r, v) VALUES ($0, 1, 1);", key_values); |
473 | 0 | CHECK_OK(processor->Run(insert_stmt)); |
474 | |
|
475 | 0 | select_stmt = Substitute("SELECT * FROM partition_hash_bcall_udt_test WHERE " |
476 | 0 | "$0(h) = $1($2)", func_name, func_name, key_values); |
477 | 0 | CHECK_OK(processor->Run(select_stmt)); |
478 | | |
479 | | // Checking result. |
480 | 0 | row_block = processor->row_block(); |
481 | 0 | ASSERT_EQ(1, row_block->row_count()); |
482 | | |
483 | | //---------------------------------------------------------------------------------------------- |
484 | | // Testing parametric types (i.e. with frozen) |
485 | | //---------------------------------------------------------------------------------------------- |
486 | 0 | CHECK_OK(processor->Run( |
487 | 0 | "CREATE TABLE partition_hash_bcall_frozen_test(" |
488 | 0 | " h1 frozen<map<int,text>>, h2 frozen<set<text>>, h3 frozen<list<int>>, " |
489 | 0 | " h4 frozen<udt_partition_hash_test>, r int, v int, PRIMARY KEY ((h1, h2, h3, h4), r))")); |
490 | | |
491 | | // Sample values to check hash value computation |
492 | 0 | key_values = "{1 : 'a', 2 : 'b'}, {'x', 'y'}, [3, 1, 2], {a : 1, b : 'foo'}"; |
493 | |
|
494 | 0 | insert_stmt = Substitute("INSERT INTO partition_hash_bcall_frozen_test " |
495 | 0 | "(h1, h2, h3, h4, r, v) VALUES ($0, 1, 1);", key_values); |
496 | 0 | CHECK_OK(processor->Run(insert_stmt)); |
497 | |
|
498 | 0 | select_stmt = Substitute("SELECT * FROM partition_hash_bcall_frozen_test WHERE " |
499 | 0 | "$0(h1, h2, h3, h4) = $1($2)", func_name, func_name, key_values); |
500 | 0 | CHECK_OK(processor->Run(select_stmt)); |
501 | | |
502 | | // Checking result. |
503 | 0 | row_block = processor->row_block(); |
504 | 0 | ASSERT_EQ(1, row_block->row_count()); |
505 | 0 | } |
506 | | |
507 | | }; |
508 | | |
509 | 0 | TEST_F(TestQLQuery, TestMissingSystemTable) { |
510 | | // Init the simulated cluster. |
511 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
512 | | |
513 | | // Get a processor. |
514 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
515 | 0 | const char* statement = "SELECT * FROM system.invalid_system_table_name"; |
516 | 0 | constexpr auto kRepetitions = 10; |
517 | 0 | for (auto i = 0; i != kRepetitions; ++i) { |
518 | 0 | CHECK_VALID_STMT(statement); |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | 0 | TEST_F(TestQLQuery, TestQLQuerySimple) { |
523 | | // Init the simulated cluster. |
524 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
525 | | |
526 | | // Get a processor. |
527 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
528 | 0 | LOG(INFO) << "Running simple query test."; |
529 | | // Create the table 1. |
530 | 0 | const char *create_stmt = |
531 | 0 | "CREATE TABLE test_table(h1 int, h2 varchar, " |
532 | 0 | "r1 int, r2 varchar, " |
533 | 0 | "v1 int, v2 varchar, " |
534 | 0 | "primary key((h1, h2), r1, r2));"; |
535 | 0 | CHECK_VALID_STMT(create_stmt); |
536 | | |
537 | | // Test NOTFOUND. Select from empty table. |
538 | 0 | CHECK_VALID_STMT("SELECT * FROM test_table"); |
539 | 0 | std::shared_ptr<QLRowBlock> empty_row_block = processor->row_block(); |
540 | 0 | CHECK_EQ(empty_row_block->row_count(), 0); |
541 | 0 | CHECK_VALID_STMT("SELECT * FROM test_table WHERE h1 = 0 AND h2 = ''"); |
542 | 0 | empty_row_block = processor->row_block(); |
543 | 0 | CHECK_EQ(empty_row_block->row_count(), 0); |
544 | | |
545 | | // Check for valid allow filtering clauses. |
546 | 0 | CHECK_VALID_STMT("SELECT * FROM test_table WHERE h1 = 0 AND h2 = '' ALLOW FILTERING"); |
547 | 0 | empty_row_block = processor->row_block(); |
548 | 0 | CHECK_EQ(empty_row_block->row_count(), 0); |
549 | |
|
550 | 0 | CHECK_VALID_STMT("SELECT h1, h2, r1, r2, v1, v2 FROM test_table " |
551 | 0 | " WHERE h1 = 7 AND h2 = 'h7' AND v1 = 1007 ALLOW FILTERING"); |
552 | 0 | empty_row_block = processor->row_block(); |
553 | 0 | CHECK_EQ(empty_row_block->row_count(), 0); |
554 | |
|
555 | 0 | CHECK_VALID_STMT("SELECT h1, h2, r1, r2, v1, v2 FROM test_table " |
556 | 0 | " WHERE h1 = 7 AND h2 = 'h7' AND v1 = 100 ALLOW FILTERING"); |
557 | 0 | empty_row_block = processor->row_block(); |
558 | 0 | CHECK_EQ(empty_row_block->row_count(), 0); |
559 | | |
560 | | // Insert 100 rows into the table. |
561 | 0 | static const int kNumRows = 100; |
562 | 0 | for (int idx = 0; idx < kNumRows; idx++) { |
563 | | // INSERT: Valid statement with column list. |
564 | 0 | string stmt = Substitute("INSERT INTO test_table(h1, h2, r1, r2, v1, v2) " |
565 | 0 | "VALUES($0, 'h$1', $2, 'r$3', $4, 'v$5');", |
566 | 0 | idx, idx, idx+100, idx+100, idx+1000, idx+1000); |
567 | 0 | CHECK_VALID_STMT(stmt); |
568 | 0 | } |
569 | 0 | LOG(INFO) << kNumRows << " rows inserted"; |
570 | | |
571 | | //------------------------------------------------------------------------------------------------ |
572 | | // Test simple query and result. |
573 | 0 | CHECK_VALID_STMT("SELECT h1, h2, r1, r2, v1, v2 FROM test_table " |
574 | 0 | " WHERE h1 = 7 AND h2 = 'h7' AND r1 = 107;"); |
575 | |
|
576 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
577 | 0 | CHECK_EQ(row_block->row_count(), 1); |
578 | 0 | const QLRow& ordered_row = row_block->row(0); |
579 | 0 | CHECK_EQ(ordered_row.column(0).int32_value(), 7); |
580 | 0 | CHECK_EQ(ordered_row.column(1).string_value(), "h7"); |
581 | 0 | CHECK_EQ(ordered_row.column(2).int32_value(), 107); |
582 | 0 | CHECK_EQ(ordered_row.column(3).string_value(), "r107"); |
583 | 0 | CHECK_EQ(ordered_row.column(4).int32_value(), 1007); |
584 | 0 | CHECK_EQ(ordered_row.column(5).string_value(), "v1007"); |
585 | | |
586 | | // Test simple query and result with different order. |
587 | 0 | CHECK_VALID_STMT("SELECT v1, v2, h1, h2, r1, r2 FROM test_table " |
588 | 0 | " WHERE h1 = 7 AND h2 = 'h7' AND r1 = 107;"); |
589 | |
|
590 | 0 | row_block = processor->row_block(); |
591 | 0 | CHECK_EQ(row_block->row_count(), 1); |
592 | 0 | const QLRow& unordered_row = row_block->row(0); |
593 | 0 | CHECK_EQ(unordered_row.column(0).int32_value(), 1007); |
594 | 0 | CHECK_EQ(unordered_row.column(1).string_value(), "v1007"); |
595 | 0 | CHECK_EQ(unordered_row.column(2).int32_value(), 7); |
596 | 0 | CHECK_EQ(unordered_row.column(3).string_value(), "h7"); |
597 | 0 | CHECK_EQ(unordered_row.column(4).int32_value(), 107); |
598 | 0 | CHECK_EQ(unordered_row.column(5).string_value(), "r107"); |
599 | | |
600 | | // Test single row query for the whole table. |
601 | 0 | for (int idx = 0; idx < kNumRows; idx++) { |
602 | | // SELECT: Valid statement with column list. |
603 | 0 | string stmt = Substitute("SELECT h1, h2, r1, r2, v1, v2 FROM test_table " |
604 | 0 | "WHERE h1 = $0 AND h2 = 'h$1' AND r1 = $2 AND r2 = 'r$3';", |
605 | 0 | idx, idx, idx+100, idx+100); |
606 | 0 | CHECK_VALID_STMT(stmt); |
607 | |
|
608 | 0 | row_block = processor->row_block(); |
609 | 0 | CHECK_EQ(row_block->row_count(), 1); |
610 | 0 | const QLRow& row = row_block->row(0); |
611 | 0 | CHECK_EQ(row.column(0).int32_value(), idx); |
612 | 0 | CHECK_EQ(row.column(1).string_value(), Substitute("h$0", idx)); |
613 | 0 | CHECK_EQ(row.column(2).int32_value(), idx + 100); |
614 | 0 | CHECK_EQ(row.column(3).string_value(), Substitute("r$0", idx + 100)); |
615 | 0 | CHECK_EQ(row.column(4).int32_value(), idx + 1000); |
616 | 0 | CHECK_EQ(row.column(5).string_value(), Substitute("v$0", idx + 1000)); |
617 | 0 | } |
618 | | |
619 | | // Test multi row query for the whole table. |
620 | | // Insert 20 rows of the same hash key into the table. |
621 | 0 | static const int kHashNumRows = 20; |
622 | 0 | int32 h1_shared = 1111111; |
623 | 0 | const string h2_shared = "h2_shared_key"; |
624 | 0 | for (int idx = 0; idx < kHashNumRows; idx++) { |
625 | | // INSERT: Valid statement with column list. |
626 | 0 | string stmt = Substitute("INSERT INTO test_table(h1, h2, r1, r2, v1, v2) " |
627 | 0 | "VALUES($0, '$1', $2, 'r$3', $4, 'v$5');", |
628 | 0 | h1_shared, h2_shared, idx+100, idx+100, idx+1000, idx+1000); |
629 | 0 | CHECK_VALID_STMT(stmt); |
630 | 0 | } |
631 | | |
632 | | // Select all 20 rows and check the values. |
633 | 0 | const string multi_select = Substitute("SELECT h1, h2, r1, r2, v1, v2 FROM test_table " |
634 | 0 | "WHERE h1 = $0 AND h2 = '$1';", |
635 | 0 | h1_shared, h2_shared); |
636 | 0 | CHECK_VALID_STMT(multi_select); |
637 | 0 | row_block = processor->row_block(); |
638 | | |
639 | | // Check the result set. |
640 | 0 | CHECK_EQ(row_block->row_count(), kHashNumRows); |
641 | 0 | for (int idx = 0; idx < kHashNumRows; idx++) { |
642 | 0 | const QLRow& row = row_block->row(idx); |
643 | 0 | CHECK_EQ(row.column(0).int32_value(), h1_shared); |
644 | 0 | CHECK_EQ(row.column(1).string_value(), h2_shared); |
645 | 0 | CHECK_EQ(row.column(2).int32_value(), idx + 100); |
646 | 0 | CHECK_EQ(row.column(3).string_value(), Substitute("r$0", idx + 100)); |
647 | 0 | CHECK_EQ(row.column(4).int32_value(), idx + 1000); |
648 | 0 | CHECK_EQ(row.column(5).string_value(), Substitute("v$0", idx + 1000)); |
649 | 0 | } |
650 | | |
651 | | // Select only 2 rows and check the values. |
652 | 0 | int limit = 2; |
653 | 0 | string limit_select = Substitute("SELECT h1, h2, r1, r2, v1, v2 FROM test_table " |
654 | 0 | "WHERE h1 = $0 AND h2 = '$1' LIMIT $2;", |
655 | 0 | h1_shared, h2_shared, limit); |
656 | 0 | CHECK_VALID_STMT(limit_select); |
657 | 0 | row_block = processor->row_block(); |
658 | | |
659 | | // Check the result set. |
660 | 0 | CHECK_EQ(row_block->row_count(), limit); |
661 | 0 | int32_t prev_r1 = 0; |
662 | 0 | string prev_r2; |
663 | 0 | for (int idx = 0; idx < limit; idx++) { |
664 | 0 | const QLRow& row = row_block->row(idx); |
665 | 0 | CHECK_EQ(row.column(0).int32_value(), h1_shared); |
666 | 0 | CHECK_EQ(row.column(1).string_value(), h2_shared); |
667 | 0 | CHECK_EQ(row.column(2).int32_value(), idx + 100); |
668 | 0 | CHECK_EQ(row.column(3).string_value(), Substitute("r$0", idx + 100)); |
669 | 0 | CHECK_EQ(row.column(4).int32_value(), idx + 1000); |
670 | 0 | CHECK_EQ(row.column(5).string_value(), Substitute("v$0", idx + 1000)); |
671 | 0 | CHECK_GT(row.column(2).int32_value(), prev_r1); |
672 | 0 | CHECK_GT(row.column(3).string_value(), prev_r2); |
673 | 0 | prev_r1 = row.column(2).int32_value(); |
674 | 0 | prev_r2 = row.column(3).string_value(); |
675 | 0 | } |
676 | |
|
677 | 0 | limit_select = Substitute("SELECT h1, h2, r1, r2, v1, v2 FROM test_table " |
678 | 0 | "WHERE h1 = $0 AND h2 = '$1' LIMIT $2 ALLOW FILTERING;", |
679 | 0 | h1_shared, h2_shared, limit); |
680 | 0 | CHECK_VALID_STMT(limit_select); |
681 | |
|
682 | 0 | const string drop_stmt = "DROP TABLE test_table;"; |
683 | 0 | EXEC_VALID_STMT(drop_stmt); |
684 | 0 | } |
685 | | |
686 | 0 | TEST_F(TestQLQuery, TestPagingState) { |
687 | | // Init the simulated cluster. |
688 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
689 | | |
690 | | // Get a processor. |
691 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
692 | |
|
693 | 0 | LOG(INFO) << "Running paging state test."; |
694 | | |
695 | | // Create table. |
696 | 0 | CHECK_VALID_STMT("CREATE TABLE t (h int, r int, v int, primary key((h), r));"); |
697 | |
|
698 | 0 | static constexpr int kNumRows = 100; |
699 | | // Insert 100 rows of the same hash key into the table. |
700 | 0 | { |
701 | 0 | for (int i = 1; i <= kNumRows; i++) { |
702 | | // INSERT: Valid statement with column list. |
703 | 0 | string stmt = Substitute("INSERT INTO t (h, r, v) VALUES ($0, $1, $2);", 1, i, 100 + i); |
704 | 0 | CHECK_VALID_STMT(stmt); |
705 | 0 | } |
706 | 0 | LOG(INFO) << kNumRows << " rows inserted"; |
707 | 0 | } |
708 | | |
709 | | // Read a single row. Verify row and that the paging state is empty. |
710 | 0 | CHECK_VALID_STMT("SELECT h, r, v FROM t WHERE h = 1 AND r = 1;"); |
711 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
712 | 0 | CHECK_EQ(row_block->row_count(), 1); |
713 | 0 | const QLRow& row = row_block->row(0); |
714 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
715 | 0 | CHECK_EQ(row.column(1).int32_value(), 1); |
716 | 0 | CHECK_EQ(row.column(2).int32_value(), 101); |
717 | 0 | CHECK(processor->rows_result()->paging_state().empty()); |
718 | | |
719 | | // Read all rows. Verify rows and that they are read in the number of pages expected. |
720 | 0 | { |
721 | 0 | StatementParameters params; |
722 | 0 | int kPageSize = 5; |
723 | 0 | params.set_page_size(kPageSize); |
724 | 0 | int page_count = 0; |
725 | 0 | int i = 0; |
726 | 0 | do { |
727 | 0 | CHECK_OK(processor->Run("SELECT h, r, v FROM t WHERE h = 1;", params)); |
728 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
729 | 0 | CHECK_EQ(row_block->row_count(), kPageSize); |
730 | 0 | for (int j = 0; j < kPageSize; j++) { |
731 | 0 | const QLRow& row = row_block->row(j); |
732 | 0 | i++; |
733 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
734 | 0 | CHECK_EQ(row.column(1).int32_value(), i); |
735 | 0 | CHECK_EQ(row.column(2).int32_value(), 100 + i); |
736 | 0 | } |
737 | 0 | page_count++; |
738 | 0 | if (processor->rows_result()->paging_state().empty()) { |
739 | 0 | break; |
740 | 0 | } |
741 | 0 | CHECK_OK(params.SetPagingState(processor->rows_result()->paging_state())); |
742 | 0 | } while (true); |
743 | 0 | CHECK_EQ(page_count, kNumRows / kPageSize); |
744 | 0 | } |
745 | | |
746 | | // Read rows with a LIMIT. Verify rows and that they are read in the number of pages expected. |
747 | 0 | { |
748 | 0 | StatementParameters params; |
749 | 0 | static constexpr int kLimit = 53; |
750 | 0 | static constexpr int kPageSize = 5; |
751 | 0 | params.set_page_size(kPageSize); |
752 | 0 | int page_count = 0; |
753 | 0 | int i = 0; |
754 | 0 | string select_stmt = Substitute("SELECT h, r, v FROM t WHERE h = 1 LIMIT $0;", kLimit); |
755 | 0 | do { |
756 | 0 | CHECK_OK(processor->Run(select_stmt, params)); |
757 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
758 | 0 | for (size_t j = 0; j < row_block->row_count(); j++) { |
759 | 0 | const QLRow& row = row_block->row(j); |
760 | 0 | i++; |
761 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
762 | 0 | CHECK_EQ(row.column(1).int32_value(), i); |
763 | 0 | CHECK_EQ(row.column(2).int32_value(), 100 + i); |
764 | 0 | } |
765 | 0 | page_count++; |
766 | 0 | if (processor->rows_result()->paging_state().empty()) { |
767 | 0 | break; |
768 | 0 | } |
769 | 0 | CHECK_EQ(row_block->row_count(), kPageSize); |
770 | 0 | CHECK_OK(params.SetPagingState(processor->rows_result()->paging_state())); |
771 | 0 | } while (true); |
772 | 0 | CHECK_EQ(i, kLimit); |
773 | 0 | CHECK_EQ(page_count, static_cast<int>(ceil(static_cast<double>(kLimit) / |
774 | 0 | static_cast<double>(kPageSize)))); |
775 | 0 | } |
776 | | |
777 | | // Insert anther 100 rows of different hash keys into the table. |
778 | 0 | { |
779 | 0 | for (int i = 1; i <= kNumRows; i++) { |
780 | | // INSERT: Valid statement with column list. |
781 | 0 | string stmt = Substitute("INSERT INTO t (h, r, v) VALUES ($0, $1, $2);", i, 100 + i, 200 + i); |
782 | 0 | CHECK_VALID_STMT(stmt); |
783 | 0 | } |
784 | 0 | LOG(INFO) << kNumRows << " rows inserted"; |
785 | 0 | } |
786 | | |
787 | | // Test full-table query without a hash key. |
788 | | |
789 | | // Read all rows. Verify rows and that they are read in the number of pages expected. |
790 | 0 | { |
791 | 0 | StatementParameters params; |
792 | 0 | int kPageSize = 5; |
793 | 0 | params.set_page_size(kPageSize); |
794 | 0 | int page_count = 0; |
795 | 0 | int row_count = 0; |
796 | 0 | int sum = 0; |
797 | 0 | do { |
798 | 0 | CHECK_OK(processor->Run("SELECT h, r, v FROM t WHERE r > 100;", params)); |
799 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
800 | 0 | for (size_t j = 0; j < row_block->row_count(); j++) { |
801 | 0 | const QLRow& row = row_block->row(j); |
802 | 0 | CHECK_EQ(row.column(0).int32_value() + 100, row.column(1).int32_value()); |
803 | 0 | sum += row.column(0).int32_value(); |
804 | 0 | row_count++; |
805 | 0 | } |
806 | 0 | page_count++; |
807 | 0 | if (processor->rows_result()->paging_state().empty()) { |
808 | 0 | break; |
809 | 0 | } |
810 | 0 | CHECK_OK(params.SetPagingState(processor->rows_result()->paging_state())); |
811 | 0 | } while (true); |
812 | 0 | CHECK_EQ(row_count, kNumRows); |
813 | | // Page count should be at least "kNumRows / kPageSize". Can be more because some pages may not |
814 | | // be fully filled depending on the hash key distribution. |
815 | 0 | CHECK_GE(page_count, kNumRows / kPageSize); |
816 | 0 | CHECK_EQ(sum, (1 + kNumRows) * kNumRows / 2); |
817 | 0 | } |
818 | | |
819 | | // Read rows with a LIMIT. Verify rows and that they are read in the number of pages expected. |
820 | 0 | { |
821 | 0 | StatementParameters params; |
822 | 0 | static constexpr int kLimit = 53; |
823 | 0 | static constexpr int kPageSize = 5; |
824 | 0 | params.set_page_size(kPageSize); |
825 | 0 | int page_count = 0; |
826 | 0 | int row_count = 0; |
827 | 0 | int sum = 0; |
828 | 0 | string select_stmt = Substitute("SELECT h, r, v FROM t WHERE r > 100 LIMIT $0;", kLimit); |
829 | 0 | do { |
830 | 0 | CHECK_OK(processor->Run(select_stmt, params)); |
831 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
832 | 0 | for (size_t j = 0; j < row_block->row_count(); j++) { |
833 | 0 | const QLRow& row = row_block->row(j); |
834 | 0 | CHECK_EQ(row.column(0).int32_value() + 100, row.column(1).int32_value()); |
835 | 0 | sum += row.column(0).int32_value(); |
836 | 0 | row_count++; |
837 | 0 | } |
838 | 0 | page_count++; |
839 | 0 | if (processor->rows_result()->paging_state().empty()) { |
840 | 0 | break; |
841 | 0 | } |
842 | 0 | CHECK_OK(params.SetPagingState(processor->rows_result()->paging_state())); |
843 | 0 | } while (true); |
844 | 0 | CHECK_EQ(row_count, kLimit); |
845 | | // Page count should be at least "kLimit / kPageSize". Can be more because some pages may not |
846 | | // be fully filled depending on the hash key distribution. Same for sum which should be at |
847 | | // least the sum of the lowest consecutive kLimit number of "h" values. Can be more. |
848 | 0 | CHECK_GE(page_count, static_cast<int>(ceil(static_cast<double>(kLimit) / |
849 | 0 | static_cast<double>(kPageSize)))); |
850 | 0 | CHECK_GE(sum, (1 + kLimit) * kLimit / 2); |
851 | 0 | } |
852 | | |
853 | | // Test queries with IN condition on hash key. |
854 | | // Verify rows and that they are read in the number of pages expected. |
855 | 0 | { |
856 | 0 | string select_stmt = "SELECT h, r, v FROM t WHERE h IN (1, 12, 23, 34, 45) AND r > 98;"; |
857 | 0 | VerifyPaginationSelect(processor, select_stmt, 2, |
858 | 0 | "{ { int32:1, int32:99, int32:199 }, { int32:1, int32:100, int32:200 } }" |
859 | 0 | "{ { int32:1, int32:101, int32:201 }, { int32:12, int32:112, int32:212 } }" |
860 | 0 | "{ { int32:23, int32:123, int32:223 }, { int32:34, int32:134, int32:234 } }" |
861 | 0 | "{ { int32:45, int32:145, int32:245 } }"); |
862 | 0 | } |
863 | | |
864 | | // Read rows with a LIMIT. Verify rows and that they are read in the number of pages expected. |
865 | 0 | { |
866 | 0 | string select_stmt = "SELECT h, r, v FROM t WHERE h IN (1, 12, 23, 34, 45) AND r > 98 LIMIT 5;"; |
867 | 0 | VerifyPaginationSelect(processor, select_stmt, 2, |
868 | 0 | "{ { int32:1, int32:99, int32:199 }, { int32:1, int32:100, int32:200 } }" |
869 | 0 | "{ { int32:1, int32:101, int32:201 }, { int32:12, int32:112, int32:212 } }" |
870 | 0 | "{ { int32:23, int32:123, int32:223 } }"); |
871 | |
|
872 | 0 | select_stmt = "SELECT h, r, v FROM t WHERE h IN (1, 12, 23, 34, 45) AND r > 98 LIMIT 2;"; |
873 | 0 | VerifyPaginationSelect(processor, select_stmt, 3, |
874 | 0 | "{ { int32:1, int32:99, int32:199 }, { int32:1, int32:100, int32:200 } }"); |
875 | 0 | } |
876 | 0 | } |
877 | | |
878 | | template <class T> |
879 | | void RunPaginationWithDescTest( |
880 | | TestQLProcessor *processor, const char* type, const std::vector<T>& values, |
881 | 0 | std::vector<QLRow>* rows) { |
882 | | /* Creating the table. */ |
883 | 0 | string create_stmt = Substitute("CREATE TABLE t_$0 (h int, r1 $1, r2 $2, v int, " |
884 | 0 | "primary key((h), r1, r2)) WITH CLUSTERING ORDER BY (r1 DESC, r2 ASC);", type, type, type); |
885 | 0 | CHECK_VALID_STMT(create_stmt); |
886 | | |
887 | | /* Inserting the values. */ |
888 | 0 | for (auto& value : values) { |
889 | 0 | string stmt = Substitute("INSERT INTO t_$0 (h, r1, r2, v) VALUES (1, $1, $2, $3);", |
890 | 0 | type, value, value, 0); |
891 | 0 | CHECK_VALID_STMT(stmt); |
892 | 0 | } |
893 | | /* Seting up low page size for reading to test paging. */ |
894 | 0 | StatementParameters params; |
895 | 0 | int kPageSize = 5; |
896 | 0 | params.set_page_size(kPageSize); |
897 | | /* Setting up range query, will include all values except minimum and maximum */ |
898 | 0 | auto min_val = values.front(); |
899 | 0 | auto max_val = values.back(); |
900 | 0 | int page_count = 0; |
901 | 0 | string select_stmt = Substitute("SELECT h, r1, r2, v FROM t_$0 WHERE h = 1 AND " |
902 | 0 | "r1 > $1 AND r2 > $2 AND r1 < $3 AND r2 < $4;", type, min_val, min_val, max_val, max_val ); |
903 | | /* Reading rows, loading the rows vector to be checked later for each case */ |
904 | 0 | do { |
905 | 0 | CHECK_OK(processor->Run(select_stmt, params)); |
906 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
907 | 0 | for (size_t j = 0; j < row_block->row_count(); j++) { |
908 | 0 | const QLRow& row = row_block->row(j); |
909 | 0 | rows->push_back(row); |
910 | 0 | } |
911 | 0 | page_count++; |
912 | 0 | if (processor->rows_result()->paging_state().empty()) { |
913 | 0 | break; |
914 | 0 | } |
915 | 0 | CHECK_OK(params.SetPagingState(processor->rows_result()->paging_state())); |
916 | 0 | } while (true); |
917 | | /* Page count should be at least "<nrRowsRead> / kPageSize". */ |
918 | | /* Can be more since some pages may not be fully filled depending on hash key distribution. */ |
919 | 0 | CHECK_GE(page_count, (values.size() - 2) / kPageSize); |
920 | 0 | } Unexecuted instantiation: _ZN2yb2ql25RunPaginationWithDescTestIiEEvPNS0_15TestQLProcessorEPKcRKNSt3__16vectorIT_NS6_9allocatorIS8_EEEEPNS7_INS_5QLRowENS9_ISE_EEEE Unexecuted instantiation: _ZN2yb2ql25RunPaginationWithDescTestINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEEvPNS0_15TestQLProcessorEPKcRKNS2_6vectorIT_NS6_ISE_EEEEPNSD_INS_5QLRowENS6_ISJ_EEEE Unexecuted instantiation: _ZN2yb2ql25RunPaginationWithDescTestIfEEvPNS0_15TestQLProcessorEPKcRKNSt3__16vectorIT_NS6_9allocatorIS8_EEEEPNS7_INS_5QLRowENS9_ISE_EEEE Unexecuted instantiation: _ZN2yb2ql25RunPaginationWithDescTestIdEEvPNS0_15TestQLProcessorEPKcRKNSt3__16vectorIT_NS6_9allocatorIS8_EEEEPNS7_INS_5QLRowENS9_ISE_EEEE |
921 | | |
922 | 0 | TEST_F(TestQLQuery, TestPaginationWithDescSort) { |
923 | | |
924 | | // Init the simulated cluster. |
925 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
926 | | |
927 | | // Get a processor. |
928 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
929 | |
|
930 | 0 | LOG(INFO) << "Running paging state test."; |
931 | | |
932 | | //------------------------------------------------------------------------------------------------ |
933 | | // Testing integer types. |
934 | | //------------------------------------------------------------------------------------------------ |
935 | 0 | { |
936 | 0 | std::vector<int> values; |
937 | 0 | for (int i = 1; i <= 100; i++) { |
938 | 0 | values.push_back(i); |
939 | 0 | } |
940 | 0 | std::vector<QLRow> rows; |
941 | 0 | auto rows_ptr = &rows; |
942 | 0 | RunPaginationWithDescTest(processor, "int", values, rows_ptr); |
943 | | // Checking rows values -- expecting results in descending order except for min and max values. |
944 | 0 | CHECK_EQ(rows.size(), values.size() - 2); |
945 | | // Results should start from second-largest value. |
946 | 0 | size_t curr_row_no = values.size() - 2; |
947 | 0 | for (auto& row : rows) { |
948 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
949 | | // Expecting results in descending order. |
950 | 0 | CHECK_EQ(row.column(1).int32_value(), values[curr_row_no]); |
951 | 0 | CHECK_EQ(row.column(2).int32_value(), values[curr_row_no]); |
952 | 0 | CHECK_EQ(row.column(3).int32_value(), 0); |
953 | 0 | curr_row_no--; |
954 | 0 | } |
955 | 0 | } |
956 | | |
957 | | //------------------------------------------------------------------------------------------------ |
958 | | // Testing timestamp type. |
959 | | //------------------------------------------------------------------------------------------------ |
960 | 0 | { |
961 | 0 | std::vector<int> values; |
962 | 0 | for (int i = 1; i <= 100; i++) { |
963 | 0 | values.push_back(i); |
964 | 0 | } |
965 | 0 | std::vector<QLRow> rows; |
966 | 0 | auto rows_ptr = &rows; |
967 | 0 | RunPaginationWithDescTest(processor, "timestamp", values, rows_ptr); |
968 | | // Checking rows values -- expecting results in descending order except for min and max values. |
969 | 0 | CHECK_EQ(rows.size(), values.size() - 2); |
970 | | // Results should start from second-largest value. |
971 | 0 | size_t curr_row_no = values.size() - 2; |
972 | 0 | int kMicrosPerMilli = 1000; |
973 | |
|
974 | 0 | for (auto& row : rows) { |
975 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
976 | | // Expecting results in descending order. |
977 | 0 | CHECK_EQ(row.column(1).timestamp_value().ToInt64(), values[curr_row_no] * kMicrosPerMilli); |
978 | 0 | CHECK_EQ(row.column(2).timestamp_value().ToInt64(), values[curr_row_no] * kMicrosPerMilli); |
979 | 0 | CHECK_EQ(row.column(3).int32_value(), 0); |
980 | 0 | curr_row_no--; |
981 | 0 | } |
982 | 0 | } |
983 | | |
984 | | //------------------------------------------------------------------------------------------------ |
985 | | // Testing inet type. |
986 | | //------------------------------------------------------------------------------------------------ |
987 | 0 | { |
988 | 0 | std::vector<string> values; |
989 | 0 | std::vector<string> input_values; |
990 | | // Insert 100 rows of the same hash key into the table. |
991 | 0 | for (int i = 1; i <= 100; i++) { |
992 | 0 | string value = "127.0.0." + std::to_string(i); |
993 | 0 | values.push_back(value); |
994 | 0 | input_values.push_back("'" + value + "'"); |
995 | 0 | } |
996 | 0 | std::vector<QLRow> rows; |
997 | 0 | auto rows_ptr = &rows; |
998 | 0 | RunPaginationWithDescTest(processor, "inet", input_values, rows_ptr); |
999 | | // Checking rows values -- expecting results in descending order except for min and max values. |
1000 | 0 | CHECK_EQ(rows.size(), values.size() - 2); |
1001 | | // Results should start from second-largest value. |
1002 | 0 | size_t curr_row_no = values.size() - 2; |
1003 | 0 | for (auto& row : rows) { |
1004 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
1005 | | // Expecting results in descending order. |
1006 | 0 | CHECK_EQ(row.column(1).inetaddress_value().ToString(), values[curr_row_no]); |
1007 | 0 | CHECK_EQ(row.column(2).inetaddress_value().ToString(), values[curr_row_no]); |
1008 | 0 | CHECK_EQ(row.column(3).int32_value(), 0); |
1009 | 0 | curr_row_no--; |
1010 | 0 | } |
1011 | 0 | } |
1012 | | |
1013 | | //------------------------------------------------------------------------------------------------ |
1014 | | // Testing uuid types. |
1015 | | //------------------------------------------------------------------------------------------------ |
1016 | 0 | { |
1017 | 0 | std::vector<string> values; |
1018 | | // Uuid prefix value -- missing last two digits. |
1019 | 0 | string uuid_prefix = "123e4567-e89b-02d3-a456-4266554400"; |
1020 | | // Insert 90 rows (two digit numbers) of the same hash key into the table. |
1021 | 0 | for (int i = 10; i < 100; i++) { |
1022 | 0 | values.push_back(uuid_prefix + std::to_string(i)); |
1023 | 0 | } |
1024 | 0 | std::vector<QLRow> rows; |
1025 | 0 | auto rows_ptr = &rows; |
1026 | 0 | RunPaginationWithDescTest(processor, "uuid", values, rows_ptr); |
1027 | | // Checking rows values -- expecting results in descending order except for min and max values. |
1028 | 0 | CHECK_EQ(rows.size(), values.size() - 2); |
1029 | | // Results should start from second-largest value. |
1030 | 0 | size_t curr_row_no = values.size() - 2; |
1031 | 0 | for (auto &row : rows) { |
1032 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
1033 | | // Expecting results in descending order. |
1034 | 0 | CHECK_EQ(row.column(1).uuid_value().ToString(), values[curr_row_no]); |
1035 | 0 | CHECK_EQ(row.column(2).uuid_value().ToString(), values[curr_row_no]); |
1036 | 0 | CHECK_EQ(row.column(3).int32_value(), 0); |
1037 | 0 | curr_row_no--; |
1038 | 0 | } |
1039 | 0 | } |
1040 | | |
1041 | | //------------------------------------------------------------------------------------------------ |
1042 | | // Testing decimal type. |
1043 | | //------------------------------------------------------------------------------------------------ |
1044 | 0 | { |
1045 | 0 | std::vector<string> values; |
1046 | | // Insert 100 rows of the same hash key into the table. |
1047 | 0 | for (int i = 10; i <= 100; i++) { |
1048 | 0 | values.push_back(std::to_string(i) + ".25"); |
1049 | 0 | } |
1050 | 0 | std::vector<QLRow> rows; |
1051 | 0 | auto rows_ptr = &rows; |
1052 | 0 | RunPaginationWithDescTest(processor, "decimal", values, rows_ptr); |
1053 | | // Checking rows values -- expecting results in descending order except for min and max values. |
1054 | 0 | CHECK_EQ(rows.size(), values.size() - 2); |
1055 | | // Results should start from second-largest value. |
1056 | 0 | size_t curr_row_no = values.size() - 2; |
1057 | 0 | for (auto &row : rows) { |
1058 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
1059 | | // Expecting results in descending order. |
1060 | 0 | util::Decimal dec; |
1061 | 0 | CHECK_OK(dec.DecodeFromComparable(row.column(1).decimal_value())); |
1062 | 0 | CHECK_EQ(dec.ToString(), values[curr_row_no]); |
1063 | 0 | CHECK_OK(dec.DecodeFromComparable(row.column(2).decimal_value())); |
1064 | 0 | CHECK_EQ(dec.ToString(), values[curr_row_no]); |
1065 | 0 | CHECK_EQ(row.column(3).int32_value(), 0); |
1066 | 0 | curr_row_no--; |
1067 | 0 | } |
1068 | 0 | } |
1069 | | |
1070 | | //------------------------------------------------------------------------------------------------ |
1071 | | // Testing float type. |
1072 | | //------------------------------------------------------------------------------------------------ |
1073 | 0 | { |
1074 | 0 | std::vector<float> values; |
1075 | | // Insert 100 rows of the same hash key into the table. |
1076 | 0 | for (int i = 10; i <= 100; i++) { |
1077 | 0 | values.push_back(i + .25); |
1078 | 0 | } |
1079 | 0 | std::vector<QLRow> rows; |
1080 | 0 | auto rows_ptr = &rows; |
1081 | 0 | RunPaginationWithDescTest(processor, "float", values, rows_ptr); |
1082 | | // Checking rows values -- expecting results in descending order except for min and max values. |
1083 | 0 | CHECK_EQ(rows.size(), values.size() - 2); |
1084 | | // Results should start from second-largest value. |
1085 | 0 | size_t curr_row_no = values.size() - 2; |
1086 | 0 | for (auto &row : rows) { |
1087 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
1088 | | // Expecting results in descending order. |
1089 | 0 | CHECK_EQ(row.column(1).float_value(), values[curr_row_no]); |
1090 | 0 | CHECK_EQ(row.column(2).float_value(), values[curr_row_no]); |
1091 | 0 | CHECK_EQ(row.column(3).int32_value(), 0); |
1092 | 0 | curr_row_no--; |
1093 | 0 | } |
1094 | 0 | } |
1095 | | |
1096 | | //------------------------------------------------------------------------------------------------ |
1097 | | // Testing double type. |
1098 | | //------------------------------------------------------------------------------------------------ |
1099 | 0 | { |
1100 | 0 | std::vector<double> values; |
1101 | | // Insert 100 rows of the same hash key into the table. |
1102 | 0 | for (int i = 10; i <= 100; i++) { |
1103 | 0 | values.push_back(i + .25); |
1104 | 0 | } |
1105 | 0 | std::vector<QLRow> rows; |
1106 | 0 | auto rows_ptr = &rows; |
1107 | 0 | RunPaginationWithDescTest(processor, "double", values, rows_ptr); |
1108 | | // Checking rows values -- expecting results in descending order except for min and max values. |
1109 | 0 | CHECK_EQ(rows.size(), values.size() - 2); |
1110 | | // Results should start from second-largest value. |
1111 | 0 | size_t curr_row_no = values.size() - 2; |
1112 | 0 | for (auto &row : rows) { |
1113 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
1114 | | // Expecting results in descending order. |
1115 | 0 | CHECK_EQ(row.column(1).double_value(), values[curr_row_no]); |
1116 | 0 | CHECK_EQ(row.column(2).double_value(), values[curr_row_no]); |
1117 | 0 | CHECK_EQ(row.column(3).int32_value(), 0); |
1118 | 0 | curr_row_no--; |
1119 | 0 | } |
1120 | 0 | } |
1121 | | |
1122 | | //------------------------------------------------------------------------------------------------ |
1123 | | // Testing string types. |
1124 | | //------------------------------------------------------------------------------------------------ |
1125 | 0 | { |
1126 | 0 | std::vector<string> values; |
1127 | 0 | std::vector<string> input_values; |
1128 | | // Insert 90 rows (two digit numbers) of the same hash key into the table. |
1129 | 0 | for (int i = 10; i < 100; i++) { |
1130 | 0 | values.push_back(std::to_string(i)); |
1131 | 0 | input_values.push_back("'" + std::to_string(i) + "'"); |
1132 | 0 | } |
1133 | 0 | std::vector<QLRow> rows; |
1134 | 0 | auto rows_ptr = &rows; |
1135 | 0 | RunPaginationWithDescTest(processor, "varchar", input_values, rows_ptr); |
1136 | | // Checking rows values -- expecting results in descending order except for min and max values. |
1137 | 0 | CHECK_EQ(rows.size(), values.size() - 2); |
1138 | | // Results should start from second-largest value. |
1139 | 0 | size_t curr_row_no = values.size() - 2; |
1140 | 0 | for (auto &row : rows) { |
1141 | 0 | CHECK_EQ(row.column(0).int32_value(), 1); |
1142 | | // Expecting results in descending order. |
1143 | 0 | CHECK_EQ(row.column(1).string_value(), values[curr_row_no]); |
1144 | 0 | CHECK_EQ(row.column(2).string_value(), values[curr_row_no]); |
1145 | 0 | CHECK_EQ(row.column(3).int32_value(), 0); |
1146 | 0 | curr_row_no--; |
1147 | 0 | } |
1148 | 0 | } |
1149 | 0 | } |
1150 | | |
1151 | 0 | TEST_F(TestQLQuery, TestQLQueryPartialHash) { |
1152 | | // Init the simulated cluster. |
1153 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1154 | | |
1155 | | // Get a processor. |
1156 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1157 | |
|
1158 | 0 | LOG(INFO) << "Running partial hash test."; |
1159 | | // Create the table 1. |
1160 | 0 | const char *create_stmt = |
1161 | 0 | "CREATE TABLE test_table(h1 int, h2 varchar, " |
1162 | 0 | "h3 bigint, h4 varchar, " |
1163 | 0 | "r1 int, r2 varchar, " |
1164 | 0 | "v1 int, v2 varchar, " |
1165 | 0 | "primary key((h1, h2, h3, h4), r1, r2));"; |
1166 | 0 | CHECK_VALID_STMT(create_stmt); |
1167 | | |
1168 | | // Test NOTFOUND. Select from empty table. |
1169 | 0 | CHECK_VALID_STMT("SELECT * FROM test_table"); |
1170 | 0 | std::shared_ptr<QLRowBlock> empty_row_block = processor->row_block(); |
1171 | 0 | CHECK_EQ(empty_row_block->row_count(), 0); |
1172 | 0 | CHECK_VALID_STMT("SELECT * FROM test_table WHERE h1 = 0 AND h2 = ''"); |
1173 | 0 | empty_row_block = processor->row_block(); |
1174 | 0 | CHECK_EQ(empty_row_block->row_count(), 0); |
1175 | | |
1176 | | // Insert 100 rows into the table. |
1177 | 0 | static const int kNumRows = 100; |
1178 | 0 | for (int idx = 0; idx < kNumRows; idx++) { |
1179 | | // INSERT: Valid statement with column list. |
1180 | 0 | string stmt = Substitute("INSERT INTO test_table(h1, h2, h3, h4, r1, r2, v1, v2) " |
1181 | 0 | "VALUES($0, 'h$1', $2, 'h$3', $4, 'r$5', $6, 'v$7');", |
1182 | 0 | idx, idx, idx+100, idx+100, idx+1000, idx+1000, idx+10000, idx+10000); |
1183 | 0 | CHECK_VALID_STMT(stmt); |
1184 | 0 | } |
1185 | 0 | LOG(INFO) << kNumRows << " rows inserted"; |
1186 | | |
1187 | | //------------------------------------------------------------------------------------------------ |
1188 | | // Check invalid case for using other operators for hash keys. |
1189 | 0 | CHECK_INVALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1190 | 0 | " WHERE h1 < 7;"); |
1191 | 0 | CHECK_INVALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1192 | 0 | " WHERE h1 > 7 AND h2 > 'h7';"); |
1193 | | |
1194 | | //------------------------------------------------------------------------------------------------ |
1195 | | // Test partial hash keys and results. |
1196 | 0 | LOG(INFO) << "Testing 3 out of 4 keys"; |
1197 | 0 | CHECK_VALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1198 | 0 | " WHERE h1 = 7 AND h2 = 'h7' AND h3 = 107;"); |
1199 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
1200 | 0 | CHECK_EQ(row_block->row_count(), 1); |
1201 | 0 | const QLRow& no_hash_row1 = row_block->row(0); |
1202 | 0 | CHECK_EQ(no_hash_row1.column(0).int32_value(), 7); |
1203 | 0 | CHECK_EQ(no_hash_row1.column(1).string_value(), "h7"); |
1204 | 0 | CHECK_EQ(no_hash_row1.column(2).int64_value(), 107); |
1205 | 0 | CHECK_EQ(no_hash_row1.column(3).string_value(), "h107"); |
1206 | 0 | CHECK_EQ(no_hash_row1.column(4).int32_value(), 1007); |
1207 | 0 | CHECK_EQ(no_hash_row1.column(5).string_value(), "r1007"); |
1208 | 0 | CHECK_EQ(no_hash_row1.column(6).int32_value(), 10007); |
1209 | 0 | CHECK_EQ(no_hash_row1.column(7).string_value(), "v10007"); |
1210 | |
|
1211 | 0 | LOG(INFO) << "Testing 2 out of 4 keys"; |
1212 | 0 | CHECK_VALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1213 | 0 | " WHERE h1 = 7 AND h2 = 'h7';"); |
1214 | 0 | row_block = processor->row_block(); |
1215 | 0 | CHECK_EQ(row_block->row_count(), 1); |
1216 | 0 | const QLRow& no_hash_row2 = row_block->row(0); |
1217 | 0 | CHECK_EQ(no_hash_row2.column(0).int32_value(), 7); |
1218 | 0 | CHECK_EQ(no_hash_row2.column(1).string_value(), "h7"); |
1219 | 0 | CHECK_EQ(no_hash_row2.column(2).int64_value(), 107); |
1220 | 0 | CHECK_EQ(no_hash_row2.column(3).string_value(), "h107"); |
1221 | 0 | CHECK_EQ(no_hash_row2.column(4).int32_value(), 1007); |
1222 | 0 | CHECK_EQ(no_hash_row2.column(5).string_value(), "r1007"); |
1223 | 0 | CHECK_EQ(no_hash_row2.column(6).int32_value(), 10007); |
1224 | 0 | CHECK_EQ(no_hash_row2.column(7).string_value(), "v10007"); |
1225 | |
|
1226 | 0 | LOG(INFO) << "Testing 1 out of 4 keys"; |
1227 | 0 | CHECK_VALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1228 | 0 | " WHERE h1 = 7;"); |
1229 | 0 | row_block = processor->row_block(); |
1230 | 0 | CHECK_EQ(row_block->row_count(), 1); |
1231 | 0 | const QLRow& no_hash_row3 = row_block->row(0); |
1232 | 0 | CHECK_EQ(no_hash_row3.column(0).int32_value(), 7); |
1233 | 0 | CHECK_EQ(no_hash_row3.column(1).string_value(), "h7"); |
1234 | 0 | CHECK_EQ(no_hash_row3.column(2).int64_value(), 107); |
1235 | 0 | CHECK_EQ(no_hash_row3.column(3).string_value(), "h107"); |
1236 | 0 | CHECK_EQ(no_hash_row3.column(4).int32_value(), 1007); |
1237 | 0 | CHECK_EQ(no_hash_row3.column(5).string_value(), "r1007"); |
1238 | 0 | CHECK_EQ(no_hash_row3.column(6).int32_value(), 10007); |
1239 | 0 | CHECK_EQ(no_hash_row3.column(7).string_value(), "v10007"); |
1240 | | |
1241 | | // Test simple query with only range key and check result. |
1242 | 0 | LOG(INFO) << "Testing 0 out of 4 keys"; |
1243 | 0 | CHECK_VALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1244 | 0 | "WHERE r1 = 1007;"); |
1245 | 0 | row_block = processor->row_block(); |
1246 | 0 | CHECK_EQ(row_block->row_count(), 1); |
1247 | 0 | const QLRow& no_hash_row4 = row_block->row(0); |
1248 | 0 | CHECK_EQ(no_hash_row4.column(0).int32_value(), 7); |
1249 | 0 | CHECK_EQ(no_hash_row4.column(1).string_value(), "h7"); |
1250 | 0 | CHECK_EQ(no_hash_row4.column(2).int64_value(), 107); |
1251 | 0 | CHECK_EQ(no_hash_row4.column(3).string_value(), "h107"); |
1252 | 0 | CHECK_EQ(no_hash_row4.column(4).int32_value(), 1007); |
1253 | 0 | CHECK_EQ(no_hash_row4.column(5).string_value(), "r1007"); |
1254 | 0 | CHECK_EQ(no_hash_row4.column(6).int32_value(), 10007); |
1255 | 0 | CHECK_EQ(no_hash_row4.column(7).string_value(), "v10007"); |
1256 | |
|
1257 | 0 | LOG(INFO) << "Testing 1 of every key each."; |
1258 | | // Test simple query with partial hash key and check result. |
1259 | 0 | CHECK_VALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1260 | 0 | "WHERE h1 = 7;"); |
1261 | 0 | row_block = processor->row_block(); |
1262 | 0 | CHECK_EQ(row_block->row_count(), 1); |
1263 | 0 | const QLRow& h1_hash_row = row_block->row(0); |
1264 | 0 | CHECK_EQ(h1_hash_row.column(0).int32_value(), 7); |
1265 | 0 | CHECK_EQ(h1_hash_row.column(1).string_value(), "h7"); |
1266 | 0 | CHECK_EQ(h1_hash_row.column(2).int64_value(), 107); |
1267 | 0 | CHECK_EQ(h1_hash_row.column(3).string_value(), "h107"); |
1268 | 0 | CHECK_EQ(h1_hash_row.column(4).int32_value(), 1007); |
1269 | 0 | CHECK_EQ(h1_hash_row.column(5).string_value(), "r1007"); |
1270 | 0 | CHECK_EQ(h1_hash_row.column(6).int32_value(), 10007); |
1271 | 0 | CHECK_EQ(h1_hash_row.column(7).string_value(), "v10007"); |
1272 | |
|
1273 | 0 | CHECK_VALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1274 | 0 | " WHERE h2 = 'h7';"); |
1275 | 0 | row_block = processor->row_block(); |
1276 | 0 | CHECK_EQ(row_block->row_count(), 1); |
1277 | 0 | const QLRow& h2_hash_row = row_block->row(0); |
1278 | 0 | CHECK_EQ(h2_hash_row.column(0).int32_value(), 7); |
1279 | 0 | CHECK_EQ(h2_hash_row.column(1).string_value(), "h7"); |
1280 | 0 | CHECK_EQ(h2_hash_row.column(2).int64_value(), 107); |
1281 | 0 | CHECK_EQ(h2_hash_row.column(3).string_value(), "h107"); |
1282 | 0 | CHECK_EQ(h2_hash_row.column(4).int32_value(), 1007); |
1283 | 0 | CHECK_EQ(h2_hash_row.column(5).string_value(), "r1007"); |
1284 | 0 | CHECK_EQ(h2_hash_row.column(6).int32_value(), 10007); |
1285 | 0 | CHECK_EQ(h2_hash_row.column(7).string_value(), "v10007"); |
1286 | |
|
1287 | 0 | CHECK_VALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1288 | 0 | " WHERE h3 = 107;"); |
1289 | 0 | row_block = processor->row_block(); |
1290 | 0 | CHECK_EQ(row_block->row_count(), 1); |
1291 | 0 | const QLRow& h3_hash_row = row_block->row(0); |
1292 | 0 | CHECK_EQ(h3_hash_row.column(0).int32_value(), 7); |
1293 | 0 | CHECK_EQ(h3_hash_row.column(1).string_value(), "h7"); |
1294 | 0 | CHECK_EQ(h3_hash_row.column(2).int64_value(), 107); |
1295 | 0 | CHECK_EQ(h3_hash_row.column(3).string_value(), "h107"); |
1296 | 0 | CHECK_EQ(h3_hash_row.column(4).int32_value(), 1007); |
1297 | 0 | CHECK_EQ(h3_hash_row.column(5).string_value(), "r1007"); |
1298 | 0 | CHECK_EQ(h3_hash_row.column(6).int32_value(), 10007); |
1299 | 0 | CHECK_EQ(h3_hash_row.column(7).string_value(), "v10007"); |
1300 | |
|
1301 | 0 | CHECK_VALID_STMT("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1302 | 0 | " WHERE h4 = 'h107';"); |
1303 | 0 | row_block = processor->row_block(); |
1304 | 0 | CHECK_EQ(row_block->row_count(), 1); |
1305 | 0 | const QLRow& h4_hash_row = row_block->row(0); |
1306 | 0 | CHECK_EQ(h4_hash_row.column(0).int32_value(), 7); |
1307 | 0 | CHECK_EQ(h4_hash_row.column(1).string_value(), "h7"); |
1308 | 0 | CHECK_EQ(h4_hash_row.column(2).int64_value(), 107); |
1309 | 0 | CHECK_EQ(h4_hash_row.column(3).string_value(), "h107"); |
1310 | 0 | CHECK_EQ(h4_hash_row.column(4).int32_value(), 1007); |
1311 | 0 | CHECK_EQ(h4_hash_row.column(5).string_value(), "r1007"); |
1312 | 0 | CHECK_EQ(h4_hash_row.column(6).int32_value(), 10007); |
1313 | 0 | CHECK_EQ(h4_hash_row.column(7).string_value(), "v10007"); |
1314 | | |
1315 | | |
1316 | | // Test multi row query for the whole table. |
1317 | | // Insert 20 rows of the same hash key into the table. |
1318 | 0 | static const int kHashNumRows = 20; |
1319 | 0 | static const int kNumFilterRows = 10; |
1320 | 0 | int32 h1_shared = 1111111; |
1321 | 0 | const string h2_shared = "h2_shared_key"; |
1322 | 0 | int64 h3_shared = 111111111; |
1323 | 0 | const string h4_shared = "h4_shared_key"; |
1324 | 0 | for (int idx = 0; idx < kHashNumRows; idx++) { |
1325 | | // INSERT: Valid statement with column list. |
1326 | 0 | string stmt = Substitute("INSERT INTO test_table(h1, h2, h3, h4, r1, r2, v1, v2) " |
1327 | 0 | "VALUES($0, '$1', $2, '$3', $4, 'r$5', $6, 'v$7');", |
1328 | 0 | h1_shared, h2_shared, h3_shared, h4_shared, |
1329 | 0 | idx+100, idx+100, idx+1000, idx+1000); |
1330 | 0 | CHECK_VALID_STMT(stmt); |
1331 | 0 | } |
1332 | | |
1333 | | // Select select rows and check the values. |
1334 | | // This test scans multiple tservers. Query result tested in java. |
1335 | | // TODO: Make QL understand paging states and continue. |
1336 | 0 | LOG(INFO) << "Testing filter with partial hash keys."; |
1337 | 0 | const string multi_select = Substitute("SELECT h1, h2, h3, h4, r1, r2, v1, v2 FROM test_table " |
1338 | 0 | "WHERE h1 = $0 AND h2 = '$1' AND r1 > $2;", |
1339 | 0 | h1_shared, h2_shared, kNumFilterRows + 100); |
1340 | 0 | CHECK_VALID_STMT(multi_select); |
1341 | |
|
1342 | 0 | const string drop_stmt = "DROP TABLE test_table;"; |
1343 | 0 | EXEC_VALID_STMT(drop_stmt); |
1344 | 0 | } |
1345 | | |
1346 | 0 | TEST_F(TestQLQuery, TestInsertWithTTL) { |
1347 | | // Init the simulated cluster. |
1348 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1349 | | |
1350 | | // Get a processor. |
1351 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1352 | |
|
1353 | 0 | CreateTableAndInsertRow(processor); |
1354 | | |
1355 | | // Sleep for 1.1 seconds and verify ttl has expired. |
1356 | 0 | std::this_thread::sleep_for(std::chrono::milliseconds(1100)); |
1357 | |
|
1358 | 0 | VerifyExpiry(processor); |
1359 | 0 | } |
1360 | | |
1361 | | TEST_F(TestQLQuery, TestUpdateWithTTL) { |
1362 | | // Init the simulated cluster. |
1363 | | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1364 | | |
1365 | | // Get a processor. |
1366 | | TestQLProcessor *processor = GetQLProcessor(); |
1367 | | |
1368 | | CreateTableAndInsertRow(processor, false); |
1369 | | |
1370 | | // Now update the row with a TTL. |
1371 | | std::string update_stmt("UPDATE test_table USING TTL 1 SET c2 = 4, c3 = 5 WHERE c1 = 1;"); |
1372 | | Status s = processor->Run(update_stmt); |
1373 | | CHECK(s.ok()); |
1374 | | |
1375 | | // Sleep for 1.1 seconds and verify ttl has expired. |
1376 | | std::this_thread::sleep_for(std::chrono::milliseconds(1100)); |
1377 | | |
1378 | | // c1 = 1 should still exist. |
1379 | | auto row_block = ExecSelect(processor); |
1380 | | QLRow& row = row_block->row(0); |
1381 | | |
1382 | | EXPECT_EQ(1, row.column(0).int32_value()); |
1383 | | EXPECT_TRUE(row.column(1).IsNull()); |
1384 | | EXPECT_TRUE(row.column(2).IsNull()); |
1385 | | |
1386 | | // Try an update by setting the primary key, which should fail since set clause can't have |
1387 | | // primary keys. |
1388 | | std::string invalid_update_stmt("UPDATE test_table USING TTL 1 SET c1 = 4 WHERE c1 = 1;"); |
1389 | | s = processor->Run(invalid_update_stmt); |
1390 | | CHECK(!s.ok()); |
1391 | | } |
1392 | | |
1393 | | // The main goal of this test is to check that the serialization/deserialization operations match |
1394 | | // The Java tests are more comprehensive but do not test the deserialization -- since they use the |
1395 | | // Cassandra deserializer instead |
1396 | | TEST_F(TestQLQuery, TestCollectionTypes) { |
1397 | | // Init the simulated cluster. |
1398 | | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1399 | | |
1400 | | // Get a processor. |
1401 | | TestQLProcessor *processor = GetQLProcessor(); |
1402 | | |
1403 | | //------------------------------------------------------------------------------------------------ |
1404 | | // Testing Map type |
1405 | | //------------------------------------------------------------------------------------------------ |
1406 | | |
1407 | | // Create table. |
1408 | | const char *map_create_stmt = |
1409 | | "CREATE TABLE map_test (id int PRIMARY KEY, v int, mp map<int, varchar>, c varchar);"; |
1410 | | Status s = processor->Run(map_create_stmt); |
1411 | | CHECK(s.ok()); |
1412 | | |
1413 | | // Insert Values |
1414 | | std::string map_insert_stmt("INSERT INTO map_test (id, v, mp, c) values " |
1415 | | "(1, 3, {21 : 'a', 22 : 'b', 23 : 'c'}, 'x');"); |
1416 | | s = processor->Run(map_insert_stmt); |
1417 | | CHECK_OK(s); |
1418 | | |
1419 | | // Check Select |
1420 | | auto map_select_stmt = "SELECT * FROM map_test WHERE id = 1"; |
1421 | | s = processor->Run(map_select_stmt); |
1422 | | CHECK(s.ok()); |
1423 | | auto map_row_block = processor->row_block(); |
1424 | | EXPECT_EQ(1, map_row_block->row_count()); |
1425 | | QLRow& map_row = map_row_block->row(0); |
1426 | | |
1427 | | // check row |
1428 | | EXPECT_EQ(1, map_row.column(0).int32_value()); |
1429 | | EXPECT_EQ(3, map_row.column(1).int32_value()); |
1430 | | EXPECT_EQ("x", map_row.column(3).string_value()); |
1431 | | // check map |
1432 | | EXPECT_EQ(InternalType::kMapValue, map_row.column(2).type()); |
1433 | | QLMapValuePB map_value = map_row.column(2).map_value(); |
1434 | | // check keys |
1435 | | EXPECT_EQ(3, map_value.keys_size()); |
1436 | | EXPECT_EQ(21, map_value.keys(0).int32_value()); |
1437 | | EXPECT_EQ(22, map_value.keys(1).int32_value()); |
1438 | | EXPECT_EQ(23, map_value.keys(2).int32_value()); |
1439 | | // check values |
1440 | | EXPECT_EQ(3, map_value.values_size()); |
1441 | | EXPECT_EQ("a", map_value.values(0).string_value()); |
1442 | | EXPECT_EQ("b", map_value.values(1).string_value()); |
1443 | | EXPECT_EQ("c", map_value.values(2).string_value()); |
1444 | | |
1445 | | //------------------------------------------------------------------------------------------------ |
1446 | | // Testing Set type |
1447 | | //------------------------------------------------------------------------------------------------ |
1448 | | |
1449 | | // Create table. |
1450 | | const char *set_create_stmt = |
1451 | | "CREATE TABLE set_test (id int PRIMARY KEY, v int, st set<int>, c varchar);"; |
1452 | | s = processor->Run(set_create_stmt); |
1453 | | CHECK(s.ok()); |
1454 | | |
1455 | | // Insert Values |
1456 | | std::string set_insert_stmt("INSERT INTO set_test (id, v, st, c) values " |
1457 | | "(1, 3, {3, 4, 1, 1, 2, 4, 2}, 'x');"); |
1458 | | s = processor->Run(set_insert_stmt); |
1459 | | CHECK_OK(s); |
1460 | | |
1461 | | // Check Select |
1462 | | auto set_select_stmt = "SELECT * FROM set_test WHERE id = 1"; |
1463 | | s = processor->Run(set_select_stmt); |
1464 | | CHECK(s.ok()); |
1465 | | auto set_row_block = processor->row_block(); |
1466 | | EXPECT_EQ(1, set_row_block->row_count()); |
1467 | | QLRow& set_row = set_row_block->row(0); |
1468 | | |
1469 | | // check row |
1470 | | EXPECT_EQ(1, set_row.column(0).int32_value()); |
1471 | | EXPECT_EQ(3, set_row.column(1).int32_value()); |
1472 | | EXPECT_EQ("x", set_row.column(3).string_value()); |
1473 | | // check set |
1474 | | EXPECT_EQ(InternalType::kSetValue, set_row.column(2).type()); |
1475 | | QLSeqValuePB set_value = set_row.column(2).set_value(); |
1476 | | // check elems |
1477 | | // returned set should have no duplicates |
1478 | | EXPECT_EQ(4, set_value.elems_size()); |
1479 | | // set elements should be in default (ascending) order |
1480 | | EXPECT_EQ(1, set_value.elems(0).int32_value()); |
1481 | | EXPECT_EQ(2, set_value.elems(1).int32_value()); |
1482 | | EXPECT_EQ(3, set_value.elems(2).int32_value()); |
1483 | | EXPECT_EQ(4, set_value.elems(3).int32_value()); |
1484 | | |
1485 | | //------------------------------------------------------------------------------------------------ |
1486 | | // Testing List type |
1487 | | //------------------------------------------------------------------------------------------------ |
1488 | | |
1489 | | // Create table. |
1490 | | const char *list_create_stmt = |
1491 | | "CREATE TABLE list_test" |
1492 | | " (id int PRIMARY KEY, v int, ls list<varchar>, c varchar, lb list<blob>);"; |
1493 | | s = processor->Run(list_create_stmt); |
1494 | | CHECK(s.ok()); |
1495 | | |
1496 | | // Insert Values |
1497 | | std::string list_insert_stmt("INSERT INTO list_test (id, v, ls, c, lb) values " |
1498 | | "(1, 3, ['c', 'd', 'a', 'b', 'd', 'b'], 'x', [0x01, 0X02, 0x33, 0x04]);"); |
1499 | | s = processor->Run(list_insert_stmt); |
1500 | | CHECK_OK(s); |
1501 | | |
1502 | | // Check Select |
1503 | | auto list_select_stmt = "SELECT * FROM list_test WHERE id = 1"; |
1504 | | s = processor->Run(list_select_stmt); |
1505 | | CHECK(s.ok()); |
1506 | | auto list_row_block = processor->row_block(); |
1507 | | EXPECT_EQ(1, list_row_block->row_count()); |
1508 | | QLRow& list_row = list_row_block->row(0); |
1509 | | |
1510 | | // check row |
1511 | | EXPECT_EQ(1, list_row.column(0).int32_value()); |
1512 | | EXPECT_EQ(3, list_row.column(1).int32_value()); |
1513 | | EXPECT_EQ("x", list_row.column(3).string_value()); |
1514 | | // check set |
1515 | | EXPECT_EQ(InternalType::kListValue, list_row.column(2).type()); |
1516 | | EXPECT_EQ(InternalType::kListValue, list_row.column(4).type()); |
1517 | | |
1518 | | // check elems |
1519 | | // lists should preserve input length (keep duplicates if any) |
1520 | | QLSeqValuePB list_value = list_row.column(2).list_value(); |
1521 | | EXPECT_EQ(6, list_value.elems_size()); |
1522 | | QLSeqValuePB blist_value = list_row.column(4).list_value(); |
1523 | | EXPECT_EQ(4, blist_value.elems_size()); |
1524 | | // list elements should preserve input order |
1525 | | EXPECT_EQ("c", list_value.elems(0).string_value()); |
1526 | | EXPECT_EQ("d", list_value.elems(1).string_value()); |
1527 | | EXPECT_EQ("a", list_value.elems(2).string_value()); |
1528 | | EXPECT_EQ("b", list_value.elems(3).string_value()); |
1529 | | EXPECT_EQ("d", list_value.elems(4).string_value()); |
1530 | | EXPECT_EQ("b", list_value.elems(5).string_value()); |
1531 | | |
1532 | | EXPECT_EQ("\x1", blist_value.elems(0).binary_value()); |
1533 | | EXPECT_EQ("\x2", blist_value.elems(1).binary_value()); |
1534 | | EXPECT_EQ("\x33", blist_value.elems(2).binary_value()); |
1535 | | EXPECT_EQ("\x4", blist_value.elems(3).binary_value()); |
1536 | | } |
1537 | | |
1538 | 0 | TEST_F(TestQLQuery, TestSystemLocal) { |
1539 | | // Init the simulated cluster. |
1540 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1541 | | |
1542 | | // Get a processor. |
1543 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1544 | |
|
1545 | 0 | auto set_select_stmt = "SELECT * FROM system.local"; |
1546 | 0 | CHECK_OK(processor->Run(set_select_stmt)); |
1547 | | |
1548 | | // Validate rows. |
1549 | 0 | auto row_block = processor->row_block(); |
1550 | 0 | EXPECT_EQ(1, row_block->row_count()); |
1551 | 0 | QLRow& row = row_block->row(0); |
1552 | 0 | EXPECT_EQ("127.0.0.3", row.column(2).inetaddress_value().ToString()); // broadcast address. |
1553 | 0 | } |
1554 | | |
1555 | 0 | TEST_F(TestQLQuery, TestSystemTablesWithRestart) { |
1556 | | // Init the simulated cluster. |
1557 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1558 | | |
1559 | | // Get a processor. |
1560 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1561 | | |
1562 | | // Verify system table query works. |
1563 | 0 | ASSERT_OK(processor->Run("SELECT * FROM system.peers")); |
1564 | | |
1565 | | // Restart the cluster. |
1566 | 0 | ASSERT_OK(cluster_->RestartSync()); |
1567 | | |
1568 | | // Verify system table query still works. |
1569 | 0 | ASSERT_OK(processor->Run("SELECT * FROM system.peers")); |
1570 | 0 | } |
1571 | | |
1572 | 0 | TEST_F(TestQLQuery, TestInvalidPeerTableEntries) { |
1573 | | // Init the simulated cluster and wait for tservers. |
1574 | 0 | int num_tservers = 3; |
1575 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster(num_tservers)); |
1576 | 0 | ASSERT_OK(cluster_->WaitForTabletServerCount(num_tservers)); |
1577 | | |
1578 | | // Verify system peers table. |
1579 | 0 | TestQLProcessor* processor = GetQLProcessor(); |
1580 | 0 | ASSERT_OK(processor->Run("SELECT * FROM system.peers")); |
1581 | 0 | std::shared_ptr<QLRowBlock> row_block = processor->row_block(); |
1582 | 0 | ASSERT_EQ(num_tservers - 1, row_block->row_count()) << row_block->ToString(); |
1583 | | |
1584 | 0 | auto ts_manager = ASSERT_RESULT(cluster_->GetLeaderMiniMaster())->master()->ts_manager(); |
1585 | 0 | NodeInstancePB instance; |
1586 | 0 | instance.set_permanent_uuid("test"); |
1587 | 0 | instance.set_instance_seqno(0); |
1588 | | |
1589 | | // Use an invalid hostname for registration. |
1590 | 0 | master::TSRegistrationPB registration; |
1591 | 0 | auto hostport_pb = registration.mutable_common()->add_private_rpc_addresses(); |
1592 | 0 | const string invalid_host = "randomhost"; |
1593 | 0 | hostport_pb->set_host(invalid_host); |
1594 | 0 | hostport_pb->set_port(123); |
1595 | |
|
1596 | 0 | ASSERT_OK(ts_manager->RegisterTS(instance, registration, CloudInfoPB(), nullptr)); |
1597 | | |
1598 | | // Verify the peers table and ensure the invalid host is not present. |
1599 | 0 | ASSERT_OK(processor->Run("SELECT * FROM system.peers")); |
1600 | 0 | row_block = processor->row_block(); |
1601 | 0 | ASSERT_EQ(num_tservers - 1, row_block->row_count()) << row_block->ToString(); |
1602 | 0 | for (const auto& row : row_block->rows()) { |
1603 | 0 | ASSERT_NE(invalid_host, row.column(0).inetaddress_value().ToString()); |
1604 | 0 | } |
1605 | 0 | } |
1606 | | |
1607 | 0 | TEST_F(TestQLQuery, TestPagination) { |
1608 | | // Init the simulated cluster. |
1609 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1610 | | |
1611 | | // Get a processor. |
1612 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1613 | | |
1614 | | // Create test table. |
1615 | 0 | CHECK_OK(processor->Run("CREATE TABLE page_test (c int PRIMARY KEY);")); |
1616 | | |
1617 | | // Insert 10 different hash keys. They should go to different tablets. |
1618 | 0 | for (int i = 1; i <= 10; i++) { |
1619 | 0 | string stmt = Substitute("INSERT INTO page_test (c) VALUES ($0);", i); |
1620 | 0 | CHECK_OK(processor->Run(stmt)); |
1621 | 0 | } |
1622 | | |
1623 | | // Do full-table query. All rows should be returned in one block. |
1624 | 0 | CHECK_VALID_STMT("SELECT * FROM page_test;"); |
1625 | |
|
1626 | 0 | auto row_block = processor->row_block(); |
1627 | 0 | EXPECT_EQ(10, row_block->row_count()); |
1628 | 0 | int sum = 0; |
1629 | 0 | for (size_t i = 0; i < row_block->row_count(); i++) { |
1630 | 0 | sum += row_block->row(i).column(0).int32_value(); |
1631 | 0 | } |
1632 | 0 | EXPECT_EQ(55, sum); |
1633 | 0 | } |
1634 | | |
1635 | 0 | TEST_F(TestQLQuery, TestTokenBcall) { |
1636 | 0 | TestPartitionHash("token"); |
1637 | 0 | } |
1638 | | |
1639 | 0 | TEST_F(TestQLQuery, TestPartitionHashBcall) { |
1640 | 0 | TestPartitionHash("partition_hash"); |
1641 | 0 | } |
1642 | | |
1643 | 0 | TEST_F(TestQLQuery, TestScanWithBoundsToken) { |
1644 | 0 | TestScanWithBoundsPartitionOps("token", std::numeric_limits<int64_t>::max(), |
1645 | 0 | std::numeric_limits<int64_t>::min()); |
1646 | 0 | } |
1647 | | |
1648 | 0 | TEST_F(TestQLQuery, TestScanWithBoundsPartitionHash) { |
1649 | 0 | TestScanWithBoundsPartitionOps("partition_hash", std::numeric_limits<uint16_t>::max(), |
1650 | 0 | std::numeric_limits<uint16_t>::min()); |
1651 | | // Get a processor. |
1652 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1653 | 0 | CHECK_INVALID_STMT("SELECT * FROM scan_bounds_test WHERE partition_hash(h1, h2) > 65536"); |
1654 | 0 | CHECK_INVALID_STMT("SELECT * FROM scan_bounds_test WHERE partition_hash(h1, h2) > -1"); |
1655 | | |
1656 | | // Test mix of partition hash and token |
1657 | 0 | CHECK_INVALID_STMT( |
1658 | 0 | "SELECT * FROM scan_bounds_test WHERE partition_hash(h1,h2) > 0 AND token(h1,h2) >= 0"); |
1659 | | // Two "less-than" bounds |
1660 | 0 | CHECK_INVALID_STMT( |
1661 | 0 | "SELECT * FROM scan_bounds_test WHERE partition_hash(h1,h2) <= 0 AND token(h1,h2) < 0"); |
1662 | | // Two "equal" conditions |
1663 | 0 | CHECK_INVALID_STMT( |
1664 | 0 | "SELECT * FROM scan_bounds_test WHERE token(h1,h2) = 0 AND partition_hash(h1,h2) = 0"); |
1665 | | // Both "equal" and "less than" conditions |
1666 | 0 | CHECK_INVALID_STMT( |
1667 | 0 | "SELECT * FROM scan_bounds_test WHERE token(h1,h2) = 0 AND partition_hash(h1,h2) <= 0"); |
1668 | | // Both "equal" and "greater than" conditions |
1669 | 0 | CHECK_INVALID_STMT( |
1670 | 0 | "SELECT * FROM scan_bounds_test WHERE partition_hash(h1,h2) = 0 AND token(h1,h2) >= 0"); |
1671 | 0 | } |
1672 | | |
1673 | 0 | TEST_F(TestQLQuery, TestInvalidGrammar) { |
1674 | | // Init the simulated cluster. |
1675 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1676 | | |
1677 | | // Get a processor. |
1678 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1679 | |
|
1680 | 0 | CHECK_INVALID_STMT("SELECT;"); |
1681 | 0 | CHECK_INVALID_STMT("SELECT 1;"); |
1682 | 0 | CHECK_INVALID_STMT("SELECT count ;"); |
1683 | 0 | CHECK_INVALID_STMT("SELECT \n \n;"); |
1684 | 0 | CHECK_INVALID_STMT("SELECT \n \n from \n \n \n ;"); |
1685 | 0 | CHECK_INVALID_STMT("SELECT * \n \n \n from \n \n ;"); |
1686 | 0 | CHECK_INVALID_STMT("SELECT * from \"long \n multiline table name wi\nth spaces \" \n ;"); |
1687 | 0 | } |
1688 | | |
1689 | 0 | TEST_F(TestQLQuery, TestDeleteColumn) { |
1690 | | //------------------------------------------------------------------------------------------------ |
1691 | | // Setting up cluster |
1692 | | //------------------------------------------------------------------------------------------------ |
1693 | | |
1694 | | // Init the simulated cluster. |
1695 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1696 | |
|
1697 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1698 | | |
1699 | | // Create test table. |
1700 | 0 | CHECK_OK(processor->Run("CREATE TABLE delete_column (h int, v1 int, v2 int," |
1701 | 0 | " PRIMARY KEY(h));")); |
1702 | |
|
1703 | 0 | client::YBTableName name(YQL_DATABASE_CQL, kDefaultKeyspaceName, "delete_column"); |
1704 | |
|
1705 | 0 | for (int i = 0; i < 2; i++) { |
1706 | 0 | string stmt = Substitute("INSERT INTO delete_column (h, v1, v2) VALUES " |
1707 | 0 | "($0, $1, $2);", i, i, i); |
1708 | 0 | CHECK_OK(processor->Run(stmt)); |
1709 | 0 | } |
1710 | | |
1711 | | // Deleting the value |
1712 | 0 | string delete_stmt = "DELETE v1 FROM delete_column WHERE h = 0"; |
1713 | 0 | CHECK_OK(processor->Run(delete_stmt)); |
1714 | |
|
1715 | 0 | string select_stmt_template = "SELECT $0 FROM delete_column WHERE h = 0"; |
1716 | | // Check that v1 is null |
1717 | 0 | CHECK_OK(processor->Run(Substitute(select_stmt_template, "v1"))); |
1718 | 0 | auto row_block = processor->row_block(); |
1719 | 0 | ASSERT_EQ(1, row_block->row_count()); |
1720 | 0 | const QLRow &row1 = row_block->row(0); |
1721 | 0 | EXPECT_TRUE(row1.column(0).IsNull()); |
1722 | | |
1723 | | // Check that v2 is 0 |
1724 | 0 | CHECK_OK(processor->Run(Substitute(select_stmt_template, "v2"))); |
1725 | 0 | row_block = processor->row_block(); |
1726 | 0 | ASSERT_EQ(1, row_block->row_count()); |
1727 | 0 | const QLRow &row2 = row_block->row(0); |
1728 | 0 | EXPECT_EQ(0, row2.column(0).int32_value()); |
1729 | | |
1730 | | // Check that primary keys and * cannot be deleted |
1731 | 0 | CHECK_INVALID_STMT("DELETE * FROM delete_column WHERE h = 0;"); |
1732 | 0 | CHECK_INVALID_STMT("DELETE h FROM delete_column WHERE h = 0;"); |
1733 | 0 | } |
1734 | | |
1735 | 0 | TEST_F(TestQLQuery, TestTtlWritetimeInWhereClauseOfSelectStatements) { |
1736 | | // Init the simulated cluster. |
1737 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1738 | |
|
1739 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1740 | |
|
1741 | 0 | CHECK_OK( |
1742 | 0 | processor->Run("CREATE TABLE ttl_writetime_test (h int, v1 int, v2 int, PRIMARY KEY(h))")); |
1743 | |
|
1744 | 0 | client::YBTableName name(YQL_DATABASE_CQL, kDefaultKeyspaceName, "ttl_writetime_test"); |
1745 | |
|
1746 | 0 | shared_ptr<client::YBTable> table; |
1747 | |
|
1748 | 0 | ASSERT_OK(client_->OpenTable(name, &table)); |
1749 | | |
1750 | | // generating input data with hash_code and inserting into table |
1751 | 0 | std::vector<std::tuple<int, int, int>> rows; |
1752 | 0 | for (int i = 0; i < 5; i++) { |
1753 | 0 | std::string i_str = std::to_string(i); |
1754 | 0 | YBPartialRow row(&table->InternalSchema()); |
1755 | 0 | CHECK_OK(row.SetInt32(0, i)); |
1756 | 0 | CHECK_OK(row.SetInt32(1, i)); |
1757 | 0 | CHECK_OK(row.SetInt32(2, i)); |
1758 | 0 | std::tuple<int, int, int> values(i, i, i); |
1759 | 0 | rows.push_back(values); |
1760 | 0 | string stmt = Substitute("INSERT INTO ttl_writetime_test (h, v1, v2) VALUES " |
1761 | 0 | "($0, $1, $2) using ttl 100;", i, i, i); |
1762 | 0 | CHECK_OK(processor->Run(stmt)); |
1763 | 0 | } |
1764 | |
|
1765 | 0 | for (int i = 5; i < 10; i++) { |
1766 | 0 | std::string i_str = std::to_string(i); |
1767 | 0 | YBPartialRow row(&table->InternalSchema()); |
1768 | 0 | CHECK_OK(row.SetInt32(0, i)); |
1769 | 0 | CHECK_OK(row.SetInt32(1, i)); |
1770 | 0 | CHECK_OK(row.SetInt32(2, i)); |
1771 | 0 | std::tuple<int, int, int> values(i, i, i); |
1772 | 0 | rows.push_back(values); |
1773 | 0 | string stmt = Substitute("INSERT INTO ttl_writetime_test (h, v1, v2) VALUES " |
1774 | 0 | "($0, $1, $2) using ttl 200;", i, i, i); |
1775 | 0 | CHECK_OK(processor->Run(stmt)); |
1776 | 0 | } |
1777 | |
|
1778 | 0 | std::sort(rows.begin(), rows.end(), |
1779 | 0 | [](const std::tuple<int, int, int>& r1, |
1780 | 0 | const std::tuple<int, int, int>& r2) -> bool { |
1781 | 0 | return std::get<0>(r1) < std::get<0>(r2); |
1782 | 0 | }); |
1783 | | |
1784 | | |
1785 | | // test that for ttl > 150, there are 5 elements that match what we expect |
1786 | 0 | string select_stmt_template = "SELECT * FROM ttl_writetime_test WHERE ttl($0) $1 $2"; |
1787 | |
|
1788 | 0 | string select_stmt = Substitute(select_stmt_template, "v1", "<", 150); |
1789 | 0 | CHECK_OK(processor->Run(select_stmt)); |
1790 | 0 | auto row_block = processor->row_block(); |
1791 | 0 | std::vector<QLRow>& returned_rows_1 = row_block->rows(); |
1792 | 0 | std::sort(returned_rows_1.begin(), returned_rows_1.end(), |
1793 | 0 | [](const QLRow &r1, |
1794 | 0 | const QLRow &r2) -> bool { |
1795 | 0 | return r1.column(0).int32_value() < r2.column(0).int32_value(); |
1796 | 0 | }); |
1797 | | // checking result |
1798 | 0 | ASSERT_EQ(5, row_block->row_count()); |
1799 | 0 | for (int i = 0; i < 5; i++) { |
1800 | 0 | QLRow &row = returned_rows_1.at(i); |
1801 | 0 | EXPECT_EQ(std::get<0>(rows[i]), row.column(0).int32_value()); |
1802 | 0 | EXPECT_EQ(std::get<1>(rows[i]), row.column(1).int32_value()); |
1803 | 0 | EXPECT_EQ(std::get<2>(rows[i]), row.column(2).int32_value()); |
1804 | 0 | } |
1805 | | |
1806 | | // Now, let us test that when we update a column with a new ttl, that it shows up |
1807 | | // Should update 2 entries |
1808 | 0 | string update_stmt = "UPDATE ttl_writetime_test using ttl 300 set v1 = 7 where h = 7;"; |
1809 | 0 | CHECK_OK(processor->Run(update_stmt)); |
1810 | 0 | update_stmt = "UPDATE ttl_writetime_test using ttl 300 set v1 = 8 where h = 8;"; |
1811 | 0 | CHECK_OK(processor->Run(update_stmt)); |
1812 | 0 | select_stmt = Substitute(select_stmt_template, "v1", ">", 250); |
1813 | 0 | CHECK_OK(processor->Run(select_stmt)); |
1814 | 0 | row_block = processor->row_block(); |
1815 | 0 | std::vector<QLRow>& returned_rows_2 = row_block->rows(); |
1816 | 0 | std::sort(returned_rows_2.begin(), returned_rows_2.end(), |
1817 | 0 | [](const QLRow &r1, |
1818 | 0 | const QLRow &r2) -> bool { |
1819 | 0 | return r1.column(0).int32_value() < r2.column(0).int32_value(); |
1820 | 0 | }); |
1821 | | // checking result |
1822 | 0 | ASSERT_EQ(2, row_block->row_count()); |
1823 | 0 | for (int i = 7; i < 9; i++) { |
1824 | 0 | QLRow &row = returned_rows_2.at(i - 7); |
1825 | 0 | EXPECT_EQ(std::get<0>(rows[i]), row.column(0).int32_value()); |
1826 | 0 | EXPECT_EQ(std::get<1>(rows[i]), row.column(1).int32_value()); |
1827 | 0 | EXPECT_EQ(std::get<2>(rows[i]), row.column(2).int32_value()); |
1828 | 0 | } |
1829 | |
|
1830 | 0 | select_stmt = Substitute(select_stmt_template, "v2", ">", 250); |
1831 | 0 | CHECK_OK(processor->Run(select_stmt)); |
1832 | 0 | row_block = processor->row_block(); |
1833 | | // checking result |
1834 | 0 | ASSERT_EQ(0, row_block->row_count()); |
1835 | 0 | } |
1836 | | |
1837 | 0 | TEST_F(TestQLQuery, TestFloatPrimaryKey) { |
1838 | | // Init the simulated cluster. |
1839 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1840 | | |
1841 | | // Get a processor. |
1842 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1843 | |
|
1844 | 0 | float my_keys[] = {0.0f, 1.5f, 1.5001f, 1.51f, 2.0f}; |
1845 | |
|
1846 | 0 | const string create_stmt = "CREATE TABLE float_key (a float, b int, primary key (a))"; |
1847 | 0 | string insert_template = "INSERT INTO float_key (a, b) VALUES ($0, $1);"; |
1848 | 0 | string select_template = "SELECT $0 FROM float_key where a = $1;"; |
1849 | |
|
1850 | 0 | CHECK_OK(processor->Run(create_stmt)); |
1851 | 0 | for (int i = 0; i < 5; i++) { |
1852 | 0 | LOG(INFO) << "Inserting " << my_keys[i]; |
1853 | 0 | CHECK_OK(processor->Run(Substitute(insert_template, my_keys[i], i))); |
1854 | 0 | } |
1855 | |
|
1856 | 0 | for (int i = 0; i < 5; i++) { |
1857 | 0 | LOG(INFO) << "Selecting " << my_keys[i]; |
1858 | 0 | CHECK_OK(processor->Run(Substitute(select_template, "*", my_keys[i]))); |
1859 | 0 | auto row_block = processor->row_block(); |
1860 | 0 | ASSERT_EQ(1, row_block->row_count()); |
1861 | 0 | std::vector<QLRow> &returned_rows = row_block->rows(); |
1862 | 0 | QLRow &row = returned_rows.at(0); |
1863 | 0 | EXPECT_EQ(my_keys[i], row.column(0).float_value()); |
1864 | 0 | EXPECT_EQ(i, row.column(1).int32_value()); |
1865 | 0 | } |
1866 | 0 | } |
1867 | | |
1868 | 0 | TEST_F(TestQLQuery, TestDoublePrimaryKey) { |
1869 | | // Init the simulated cluster. |
1870 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1871 | | |
1872 | | // Get a processor. |
1873 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1874 | |
|
1875 | 0 | double my_keys[] = {0.0l, 1.5l, 1.5000000001l, 1.51l, 2.0l}; |
1876 | | // Assert that the two numbers are equal as floats but not equal as doubles. |
1877 | 0 | ASSERT_EQ(1.5f, 1.5000000001f); |
1878 | 0 | ASSERT_LT(1.5l, 1.5000000001l); |
1879 | |
|
1880 | 0 | const string create_stmt = "CREATE TABLE double_key (a double, b int, primary key (a))"; |
1881 | 0 | string insert_template = "INSERT INTO double_key (a, b) VALUES ($0, $1);"; |
1882 | 0 | string select_template = "SELECT $0 FROM double_key where a = $1;"; |
1883 | |
|
1884 | 0 | CHECK_OK(processor->Run(create_stmt)); |
1885 | 0 | for (int i = 0; i < 5; i++) { |
1886 | 0 | LOG(INFO) << "Inserting " << my_keys[i]; |
1887 | 0 | CHECK_OK(processor->Run(Substitute(insert_template, my_keys[i], i))); |
1888 | 0 | } |
1889 | |
|
1890 | 0 | for (int i = 0; i < 5; i++) { |
1891 | 0 | LOG(INFO) << "Selecting " << my_keys[i]; |
1892 | 0 | CHECK_OK(processor->Run(Substitute(select_template, "*", my_keys[i]))); |
1893 | 0 | auto row_block = processor->row_block(); |
1894 | 0 | ASSERT_EQ(1, row_block->row_count()); |
1895 | 0 | std::vector<QLRow> &returned_rows = row_block->rows(); |
1896 | 0 | QLRow &row = returned_rows.at(0); |
1897 | 0 | EXPECT_EQ(my_keys[i], row.column(0).double_value()); |
1898 | 0 | EXPECT_EQ(i, row.column(1).int32_value()); |
1899 | 0 | } |
1900 | 0 | } |
1901 | | |
1902 | | |
1903 | 0 | void verifyJson(std::shared_ptr<QLRowBlock> row_block) { |
1904 | | // Verify. |
1905 | 0 | ASSERT_EQ(1, row_block->row_count()); |
1906 | 0 | std::vector<QLRow> &returned_rows = row_block->rows(); |
1907 | 0 | QLRow &row = returned_rows.at(0); |
1908 | | // All spaces are removed by rapidjson writer. |
1909 | 0 | string json; |
1910 | 0 | common::Jsonb jsonb(row.column(1).jsonb_value()); |
1911 | 0 | ASSERT_OK(jsonb.ToJsonString(&json)); |
1912 | 0 | EXPECT_EQ("{\"a\":1,\"b\":2}", json); |
1913 | 0 | faststring buffer; |
1914 | 0 | row.column(1).Serialize(QLType::Create(DataType::JSONB), YQL_CLIENT_CQL, &buffer); |
1915 | 0 | int32_t len = 0; |
1916 | 0 | Slice data(buffer); |
1917 | 0 | ASSERT_OK(CQLDecodeNum(sizeof(len), NetworkByteOrder::Load32, &data, &len)); |
1918 | 0 | string val; |
1919 | 0 | ASSERT_OK(CQLDecodeBytes(len, &data, &val)); |
1920 | 0 | EXPECT_EQ("{\"a\":1,\"b\":2}", val); |
1921 | 0 | } |
1922 | | |
1923 | 0 | TEST_F(TestQLQuery, TestJson) { |
1924 | | // Init the simulated cluster. |
1925 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1926 | | |
1927 | | // Get a processor. |
1928 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1929 | 0 | CHECK_OK(processor->Run("CREATE TABLE test_json (k1 int PRIMARY KEY, data jsonb)")); |
1930 | 0 | CHECK_OK(processor->Run( |
1931 | 0 | "INSERT INTO test_json (k1, data) values (1, '{ \"a\" : 1, \"b\" : 2 }')")); |
1932 | 0 | CHECK_OK(processor->Run("SELECT * FROM test_json")); |
1933 | 0 | verifyJson(processor->row_block()); |
1934 | |
|
1935 | 0 | CHECK_OK(processor->Run("SELECT * FROM test_json WHERE k1=1 AND data='{\"a\":1,\"b\":2}'")); |
1936 | 0 | verifyJson(processor->row_block()); |
1937 | |
|
1938 | 0 | CHECK_OK(processor->Run("SELECT * FROM test_json WHERE k1=1 AND data='{\"a\" : 1,\"b\" : 2}'")); |
1939 | 0 | verifyJson(processor->row_block()); |
1940 | |
|
1941 | 0 | CHECK_OK(processor->Run("SELECT * FROM test_json WHERE k1=1 AND data='{\"b\" : 2,\"a\" : 1}'")); |
1942 | 0 | verifyJson(processor->row_block()); |
1943 | |
|
1944 | 0 | CHECK_OK(processor->Run("SELECT * FROM test_json WHERE k1=1 AND data->'a' = '1'")); |
1945 | 0 | verifyJson(processor->row_block()); |
1946 | |
|
1947 | 0 | CHECK_OK(processor->Run("SELECT * FROM test_json WHERE k1=1 AND data->>'a' = '1'")); |
1948 | 0 | verifyJson(processor->row_block()); |
1949 | |
|
1950 | 0 | ASSERT_NOK(processor->Run("CREATE TABLE test_json1 (k1 jsonb PRIMARY KEY, data jsonb)")); |
1951 | 0 | ASSERT_NOK(processor->Run("CREATE TABLE test_json2 (h1 int, r1 jsonb, c1 int, PRIMARY KEY ((h1)" |
1952 | 0 | ", r1))")); |
1953 | 0 | } |
1954 | | |
1955 | 0 | TEST_F(TestQLQuery, TestJsonUpdate) { |
1956 | | // Init the simulated cluster. |
1957 | 0 | ASSERT_NO_FATALS(CreateSimulatedCluster()); |
1958 | | |
1959 | | // Get a processor. |
1960 | 0 | TestQLProcessor *processor = GetQLProcessor(); |
1961 | 0 | ASSERT_OK(processor->Run("CREATE TABLE test_json (k1 int PRIMARY KEY, data jsonb)")); |
1962 | 0 | ASSERT_OK(processor->Run( |
1963 | 0 | "INSERT INTO test_json (k1, data) values (1, '{ \"a\" : 1, \"b\" : 2 }')")); |
1964 | 0 | ASSERT_OK(processor->Run("SELECT * FROM test_json")); |
1965 | 0 | verifyJson(processor->row_block()); |
1966 | |
|
1967 | 0 | ASSERT_OK(processor->Run("UPDATE test_json SET data->'a' = '100' WHERE k1 = 1")); |
1968 | 0 | ASSERT_NOK(processor->Run("UPDATE test_json SET data->'new-field'->'c' = '100' WHERE k1 = 1")); |
1969 | 0 | ASSERT_OK(processor->Run("UPDATE test_json SET data->'new-field' = '100' WHERE k1 = 1")); |
1970 | |
|
1971 | 0 | ASSERT_OK(processor->Run("UPDATE test_json SET data = '{ \"a\": 2, \"b\": 4 }' WHERE k1 = 2")); |
1972 | | |
1973 | | // Setting primitive value in JSON column should work |
1974 | 0 | ASSERT_OK(processor->Run("UPDATE test_json SET data='true' WHERE k1 = 1")); |
1975 | | // Trying to update primitive value in JSON column using field name should error out |
1976 | 0 | ASSERT_NOK(processor->Run("UPDATE test_json SET data->'a' WHERE k1 = 1")); |
1977 | 0 | } |
1978 | | |
1979 | | } // namespace ql |
1980 | | } // namespace yb |