16
16
#include < clickhouse/client.h>
17
17
18
18
#include < gtest/gtest.h>
19
+ #include < initializer_list>
20
+ #include < memory>
21
+ #include < type_traits>
19
22
20
23
#include " utils.h"
21
24
#include " roundtrip_column.h"
@@ -46,10 +49,12 @@ std::ostream& operator<<(std::ostream& ostr, const Type::Code& type_code) {
46
49
template <typename ColumnTypeT,
47
50
typename std::shared_ptr<ColumnTypeT> (*CreatorFunction)(),
48
51
typename GeneratorValueType,
49
- typename std::vector<GeneratorValueType> (*GeneratorFunc )()>
52
+ typename std::vector<GeneratorValueType> (*GeneratorFunction )()>
50
53
struct GenericColumnTestCase
51
54
{
52
55
using ColumnType = ColumnTypeT;
56
+ static constexpr auto Creator = CreatorFunction;
57
+ static constexpr auto Generator = GeneratorFunction;
53
58
54
59
static auto createColumn ()
55
60
{
@@ -58,7 +63,7 @@ struct GenericColumnTestCase
58
63
59
64
static auto generateValues ()
60
65
{
61
- return GeneratorFunc ();
66
+ return GeneratorFunction ();
62
67
}
63
68
};
64
69
@@ -92,7 +97,7 @@ class GenericColumnTest : public testing::Test {
92
97
return std::tuple{column, values};
93
98
}
94
99
95
- static std::optional<std::string> SkipTest (clickhouse::Client& client) {
100
+ static std::optional<std::string> CheckIfShouldSkipTest (clickhouse::Client& client) {
96
101
if constexpr (std::is_same_v<ColumnType, ColumnDate32>) {
97
102
// Date32 first appeared in v21.9.2.17-stable
98
103
const auto server_info = client.GetServerInfo ();
@@ -113,6 +118,33 @@ class GenericColumnTest : public testing::Test {
113
118
}
114
119
return std::nullopt;
115
120
}
121
+
122
+ template <typename ColumnType>
123
+ static void TestColumnRoundtrip (const std::shared_ptr<ColumnType> & column, const ClientOptions & client_options)
124
+ {
125
+ SCOPED_TRACE (::testing::Message (" Column type: " ) << column->GetType ().GetName ());
126
+ SCOPED_TRACE (::testing::Message (" Client options: " ) << client_options);
127
+
128
+ clickhouse::Client client (client_options);
129
+
130
+ if (auto message = CheckIfShouldSkipTest (client)) {
131
+ GTEST_SKIP () << *message;
132
+ }
133
+
134
+ auto result_typed = RoundtripColumnValues (client, column)->template AsStrict <ColumnType>();
135
+ EXPECT_TRUE (CompareRecursive (*column, *result_typed));
136
+ }
137
+
138
+
139
+ template <typename ColumnType, typename CompressionMethods>
140
+ static void TestColumnRoundtrip (const ColumnType & column, const ClientOptions & client_options, CompressionMethods && compression_methods)
141
+ {
142
+ for (auto compressionMethod : compression_methods)
143
+ {
144
+ ClientOptions new_options = ClientOptions (client_options).SetCompressionMethod (compressionMethod);
145
+ TestColumnRoundtrip (column, new_options);
146
+ }
147
+ }
116
148
};
117
149
118
150
// Luckily all (non-data copying/moving) constructors have size_t params.
@@ -184,7 +216,17 @@ using TestCases = ::testing::Types<
184
216
DecimalColumnTestCase<ColumnDecimal, 12 , 9 >,
185
217
186
218
DecimalColumnTestCase<ColumnDecimal, 6 , 0 >,
187
- DecimalColumnTestCase<ColumnDecimal, 6 , 3 >
219
+ DecimalColumnTestCase<ColumnDecimal, 6 , 3 >,
220
+
221
+ GenericColumnTestCase<ColumnLowCardinalityT<ColumnString>, &makeColumn<ColumnLowCardinalityT<ColumnString>>, std::string, &MakeStrings>
222
+
223
+ // Array(String)
224
+ // GenericColumnTestCase<ColumnArrayT<ColumnString>, &makeColumn<ColumnArrayT<ColumnString>>, std::vector<std::string>, &MakeArrays<std::string, &MakeStrings>>
225
+
226
+ // // Array(Array(String))
227
+ // GenericColumnTestCase<ColumnArrayT<ColumnArrayT<ColumnString>>, &makeColumn<ColumnArrayT<ColumnArrayT<ColumnString>>>,
228
+ // std::vector<std::vector<std::string>>,
229
+ // &MakeArrays<std::vector<std::string>, &MakeArrays<std::string, &MakeStrings>>>
188
230
>;
189
231
190
232
TYPED_TEST_SUITE (GenericColumnTest, TestCases);
@@ -222,7 +264,7 @@ TYPED_TEST(GenericColumnTest, EmptyColumn) {
222
264
223
265
TYPED_TEST (GenericColumnTest, Append) {
224
266
auto column = this ->MakeColumn ();
225
- const auto values = this ->GenerateValues (100 );
267
+ const auto values = this ->GenerateValues (10'000 );
226
268
227
269
for (const auto & v : values) {
228
270
EXPECT_NO_THROW (column->Append (v));
@@ -259,10 +301,17 @@ inline auto convertValueForGetItem(const ColumnType& col, ValueType&& t) {
259
301
}
260
302
261
303
TYPED_TEST (GenericColumnTest, GetItem) {
262
- auto [column, values] = this ->MakeColumnWithValues (100 );
304
+ auto [column, values] = this ->MakeColumnWithValues (10'000 );
263
305
264
306
ASSERT_EQ (values.size (), column->Size ());
265
- ASSERT_EQ (column->GetItem (0 ).type , column->GetType ().GetCode ());
307
+ const auto wrapping_types = std::set<Type::Code>{
308
+ Type::Code::LowCardinality, Type::Code::Array, Type::Code::Nullable
309
+ };
310
+
311
+ // For wrapping types, type of ItemView can be different from type of column
312
+ if (wrapping_types.find (column->GetType ().GetCode ()) == wrapping_types.end () ) {
313
+ EXPECT_EQ (column->GetItem (0 ).type , column->GetType ().GetCode ());
314
+ }
266
315
267
316
for (size_t i = 0 ; i < values.size (); ++i) {
268
317
const auto v = convertValueForGetItem (*column, values[i]);
@@ -274,7 +323,7 @@ TYPED_TEST(GenericColumnTest, GetItem) {
274
323
}
275
324
276
325
TYPED_TEST (GenericColumnTest, Slice) {
277
- auto [column, values] = this ->MakeColumnWithValues (100 );
326
+ auto [column, values] = this ->MakeColumnWithValues (10'000 );
278
327
279
328
auto untyped_slice = column->Slice (0 , column->Size ());
280
329
auto slice = untyped_slice->template AsStrict <typename TestFixture::ColumnType>();
@@ -286,7 +335,7 @@ TYPED_TEST(GenericColumnTest, Slice) {
286
335
}
287
336
288
337
TYPED_TEST (GenericColumnTest, CloneEmpty) {
289
- auto [column, values] = this ->MakeColumnWithValues (100 );
338
+ auto [column, values] = this ->MakeColumnWithValues (10'000 );
290
339
EXPECT_EQ (values.size (), column->Size ());
291
340
292
341
auto clone_untyped = column->CloneEmpty ();
@@ -298,15 +347,15 @@ TYPED_TEST(GenericColumnTest, CloneEmpty) {
298
347
}
299
348
300
349
TYPED_TEST (GenericColumnTest, Clear) {
301
- auto [column, values] = this ->MakeColumnWithValues (100 );
350
+ auto [column, values] = this ->MakeColumnWithValues (10'000 );
302
351
EXPECT_EQ (values.size (), column->Size ());
303
352
304
353
column->Clear ();
305
354
EXPECT_EQ (0u , column->Size ());
306
355
}
307
356
308
357
TYPED_TEST (GenericColumnTest, Swap) {
309
- auto [column_A, values] = this ->MakeColumnWithValues (100 );
358
+ auto [column_A, values] = this ->MakeColumnWithValues (10'000 );
310
359
auto column_B = this ->MakeColumn ();
311
360
312
361
column_A->Swap (*column_B);
@@ -318,18 +367,21 @@ TYPED_TEST(GenericColumnTest, Swap) {
318
367
TYPED_TEST (GenericColumnTest, LoadAndSave) {
319
368
auto [column_A, values] = this ->MakeColumnWithValues (100 );
320
369
321
- char buffer[4096 ] = {' \0 ' };
370
+ // large buffer since we have pretty big values for String column
371
+ auto const BufferSize = 10 *1024 *1024 ;
372
+ std::unique_ptr<char []> buffer = std::make_unique<char []>(BufferSize);
373
+ memset (buffer.get (), 0 , BufferSize);
322
374
{
323
- ArrayOutput output (buffer, sizeof (buffer) );
375
+ ArrayOutput output (buffer. get (), BufferSize );
324
376
// Save
325
- EXPECT_NO_THROW (column_A->Save (&output));
377
+ ASSERT_NO_THROW (column_A->Save (&output));
326
378
}
327
379
328
380
auto column_B = this ->MakeColumn ();
329
381
{
330
- ArrayInput input (buffer, sizeof (buffer) );
382
+ ArrayInput input (buffer. get (), BufferSize );
331
383
// Load
332
- EXPECT_TRUE (column_B->Load (&input, values.size ()));
384
+ ASSERT_TRUE (column_B->Load (&input, values.size ()));
333
385
}
334
386
335
387
EXPECT_TRUE (CompareRecursive (*column_A, *column_B));
@@ -342,25 +394,28 @@ const auto LocalHostEndpoint = ClientOptions()
342
394
.SetPassword( getEnvOrDefault(" CLICKHOUSE_PASSWORD" , " " ))
343
395
.SetDefaultDatabase(getEnvOrDefault(" CLICKHOUSE_DB" , " default" ));
344
396
397
+ const auto AllCompressionMethods = {
398
+ clickhouse::CompressionMethod::None,
399
+ clickhouse::CompressionMethod::LZ4
400
+ };
401
+
345
402
TYPED_TEST (GenericColumnTest, RoundTrip) {
346
- auto [column, values] = this ->MakeColumnWithValues (100 );
403
+ auto [column, values] = this ->MakeColumnWithValues (10'000 );
347
404
EXPECT_EQ (values.size (), column->Size ());
348
405
349
- clickhouse::Client client (LocalHostEndpoint);
350
-
351
- if (auto message = this ->SkipTest (client)) {
352
- GTEST_SKIP () << *message;
353
- }
354
-
355
- auto result_typed = RoundtripColumnValues (client, column)->template AsStrict <typename TestFixture::ColumnType>();
356
- EXPECT_TRUE (CompareRecursive (*column, *result_typed));
406
+ this ->TestColumnRoundtrip (column, LocalHostEndpoint, AllCompressionMethods);
357
407
}
358
408
359
- TYPED_TEST (GenericColumnTest, NulableT_RoundTrip ) {
409
+ TYPED_TEST (GenericColumnTest, NullableT_RoundTrip ) {
360
410
using NullableType = ColumnNullableT<typename TestFixture::ColumnType>;
361
411
362
- auto column = std::make_shared<NullableType>(this ->MakeColumn ());
363
- auto values = this ->GenerateValues (100 );
412
+ auto non_nullable_column = this ->MakeColumn ();
413
+ if (non_nullable_column->GetType ().GetCode () == Type::Code::LowCardinality)
414
+ // TODO (vnemkov): wrap as ColumnLowCardinalityT<ColumnNullableT<NestedColumn>> instead of ColumnNullableT<ColumnLowCardinalityT<NestedColumn>>
415
+ GTEST_SKIP () << " Can't have " << non_nullable_column->GetType ().GetName () << " in Nullable" ;
416
+
417
+ auto column = std::make_shared<NullableType>(std::move (non_nullable_column));
418
+ auto values = this ->GenerateValues (10'000 );
364
419
365
420
FromVectorGenerator<bool > is_null ({true , false });
366
421
for (size_t i = 0 ; i < values.size (); ++i) {
@@ -371,12 +426,24 @@ TYPED_TEST(GenericColumnTest, NulableT_RoundTrip) {
371
426
}
372
427
}
373
428
374
- clickhouse::Client client (LocalHostEndpoint);
429
+ this ->TestColumnRoundtrip (column, LocalHostEndpoint, AllCompressionMethods);
430
+ }
431
+
432
+ TYPED_TEST (GenericColumnTest, ArrayT_RoundTrip) {
433
+ using ColumnArrayType = ColumnArrayT<typename TestFixture::ColumnType>;
375
434
376
- if (auto message = this ->SkipTest (client)) {
377
- GTEST_SKIP () << *message;
435
+ auto [nested_column, values] = this ->MakeColumnWithValues (100 );
436
+
437
+ auto column = std::make_shared<ColumnArrayType>(nested_column->CloneEmpty ()->template As <typename TestFixture::ColumnType>());
438
+ for (size_t i = 0 ; i < values.size (); ++i)
439
+ {
440
+ const std::vector<std::decay_t <decltype (values[0 ])>> row{values.begin (), values.begin () + i};
441
+ column->Append (values.begin (), values.begin () + i);
442
+
443
+ EXPECT_TRUE (CompareRecursive (row, (*column)[column->Size () - 1 ]));
378
444
}
445
+ EXPECT_EQ (values.size (), column->Size ());
379
446
380
- auto result_typed = WrapColumn<NullableType>(RoundtripColumnValues (client, column));
381
- EXPECT_TRUE (CompareRecursive (*column, *result_typed));
447
+ this ->TestColumnRoundtrip (column, LocalHostEndpoint, AllCompressionMethods);
382
448
}
449
+
0 commit comments