@@ -10,6 +10,8 @@ namespace
1010using namespace clickhouse ;
1111}
1212
13+ #define DBMS_MIN_REVISION_WITH_CUSTOM_SERIALIZATION 54454
14+
1315static const auto localHostEndpoint = ClientOptions()
1416 .SetHost( getEnvOrDefault(" CLICKHOUSE_HOST" , " localhost" ))
1517 .SetPort( getEnvOrDefault<size_t >(" CLICKHOUSE_PORT" , " 9000" ))
@@ -30,19 +32,31 @@ class SparseCase : public testing::Test {
3032 }
3133
3234 template <typename T>
33- std::shared_ptr<T> createTableWithOneColumn ( )
35+ bool createTable ( std::shared_ptr<T> col )
3436 {
35- auto col = std::make_shared<T>();
3637 const auto type_name = col->GetType ().GetName ();
3738
3839 client_->Execute (" DROP TABLE IF EXISTS " + table_name + " ;" );
39- client_->Execute (" CREATE TABLE IF NOT EXISTS " + table_name + " ( id UInt64," + column_name + " " + type_name + " )"
40- " ENGINE = MergeTree ORDER BY id "
41- " SETTINGS index_granularity = 32, "
42- " ratio_of_defaults_for_sparse_serialization = 0.1;" );
40+ try {
41+ client_->Execute (" CREATE TABLE IF NOT EXISTS " + table_name + " ( id UInt64," + column_name + " " + type_name + " )"
42+ " ENGINE = MergeTree ORDER BY id "
43+ " SETTINGS index_granularity = 32, "
44+ " ratio_of_defaults_for_sparse_serialization = 0.1;" );
45+ } catch (const std::exception & e) {
46+ std::cerr << " Got error while create table: " << e.what () << std::endl;
47+ // DB::Exception: clickhouse_cpp_cicd: Cannot execute query in readonly mode
48+ if (std::string (e.what ()).find (" Cannot execute query in readonly mode" ) != std::string::npos) {
49+ return false ;
50+ }
51+ // DB::Exception: clickhouse_cpp_cicd: Not enough privileges. To execute this query it's necessary to have grant CREATE TABLE ON default.test_clickhouse_cpp_test_ut_sparse_table
52+ if (std::string (e.what ()).find (" Not enough privileges" ) != std::string::npos) {
53+ return false ;
54+ }
55+ throw ;
56+ }
4357
4458 client_->Execute (" SYSTEM STOP MERGES test_clickhouse_sparse_table;" );
45- return col ;
59+ return true ;
4660 }
4761
4862 std::string getOneColumnSelectQuery () const
@@ -77,9 +91,15 @@ class SparseCase : public testing::Test {
7791
7892TEST_F (SparseCase, UInt64_Load) {
7993
80- createTableWithOneColumn<ColumnUInt64>();
94+ if (client_->GetServerInfo ().revision < DBMS_MIN_REVISION_WITH_CUSTOM_SERIALIZATION) {
95+ GTEST_SKIP ();
96+ }
97+
98+ if (!createTable (std::make_shared<ColumnUInt64>())) {
99+ GTEST_SKIP ();
100+ }
81101
82- client_->Execute (" INSERT INTO " + table_name +" "
102+ client_->Execute (" INSERT INTO " + table_name +
83103 " SELECT number, "
84104 " if (number % 10 = 0, number, 0)"
85105 " FROM numbers(1000);" );
@@ -95,6 +115,7 @@ TEST_F(SparseCase, UInt64_Load) {
95115 ASSERT_EQ (1U , block.GetColumnCount ());
96116 ASSERT_TRUE (block[0 ]->GetType ().IsEqual (Type::CreateSimple<uint64_t >()));
97117 auto cl = block[0 ]->AsStrict <ColumnUInt64>();
118+ ASSERT_EQ (cl->GetSerialization ()->GetKind (), Serialization::Kind::SPARSE);
98119 for (size_t i = 0 ; i < 1000 ; ++i) {
99120 if (i % 10 == 0 ) {
100121 EXPECT_EQ (cl->At (i), i);
@@ -103,6 +124,128 @@ TEST_F(SparseCase, UInt64_Load) {
103124 }
104125 }
105126 });
127+ }
128+
129+ TEST_F (SparseCase, String_Load) {
130+
131+ if (client_->GetServerInfo ().revision < DBMS_MIN_REVISION_WITH_CUSTOM_SERIALIZATION) {
132+ GTEST_SKIP ();
133+ }
134+
135+ if (!createTable (std::make_shared<ColumnString>())) {
136+ GTEST_SKIP ();
137+ }
138+
139+ client_->Execute (" INSERT INTO " + table_name +
140+ " SELECT number, "
141+ " if (number % 10 = 0, toString(number), '')"
142+ " FROM numbers(1000);" );
143+
144+ checkSerializationKind ();
145+
146+ client_->Select (getOneColumnSelectQuery (),
147+ [&](const Block& block) {
148+ // std::cerr << PrettyPrintBlock{block} << std::endl;
149+ if (block.GetRowCount () == 0 )
150+ return ;
151+ EXPECT_EQ (1000u , block.GetRowCount ());
152+ ASSERT_EQ (1U , block.GetColumnCount ());
153+ ASSERT_TRUE (block[0 ]->GetType ().IsEqual (Type::CreateString ()));
154+ auto cl = block[0 ]->AsStrict <ColumnString>();
155+ ASSERT_EQ (cl->GetSerialization ()->GetKind (), Serialization::Kind::SPARSE);
156+ for (size_t i = 0 ; i < 1000 ; ++i) {
157+ if (i % 10 == 0 ) {
158+ EXPECT_EQ (cl->At (i), std::to_string (i));
159+ } else {
160+ EXPECT_EQ (cl->At (i), " " );
161+ }
162+ }
163+ });
164+ }
165+
166+ TEST_F (SparseCase, FixedString_Load) {
167+ const size_t FixedStringSize = 10 ;
168+
169+ if (client_->GetServerInfo ().revision < DBMS_MIN_REVISION_WITH_CUSTOM_SERIALIZATION) {
170+ GTEST_SKIP ();
171+ }
172+
173+ if (!createTable (std::make_shared<ColumnFixedString>(FixedStringSize))) {
174+ GTEST_SKIP ();
175+ }
176+
177+ client_->Execute (" INSERT INTO " + table_name +
178+ " SELECT number, "
179+ " if (number % 10 = 0, toString(number), '')"
180+ " FROM numbers(1000);" );
181+
182+ checkSerializationKind ();
183+
184+ auto rpad = [](const std::string& val) {
185+ std::string res = val;
186+ res.append (std::string (FixedStringSize - res.size (), ' \0 ' ));
187+ return res;
188+ };
189+
190+ client_->Select (getOneColumnSelectQuery (),
191+ [&](const Block& block) {
192+ // std::cerr << PrettyPrintBlock{block} << std::endl;
193+ if (block.GetRowCount () == 0 )
194+ return ;
195+ EXPECT_EQ (1000u , block.GetRowCount ());
196+ ASSERT_EQ (1U , block.GetColumnCount ());
197+ ASSERT_TRUE (block[0 ]->GetType ().IsEqual (Type::CreateString (FixedStringSize)));
198+ auto cl = block[0 ]->AsStrict <ColumnFixedString>();
199+ EXPECT_EQ (cl->GetSerialization ()->GetKind (), Serialization::Kind::SPARSE);
200+ for (size_t i = 0 ; i < 1000 ; ++i) {
201+ if (i % 10 == 0 ) {
202+ EXPECT_EQ (cl->At (i), rpad (std::to_string (i)));
203+ } else {
204+ EXPECT_EQ (cl->At (i), rpad (" " ));
205+ }
206+ }
207+ });
208+ }
106209
107210
211+ TEST_F (SparseCase, Tuple_Load) {
212+
213+ if (client_->GetServerInfo ().revision < DBMS_MIN_REVISION_WITH_CUSTOM_SERIALIZATION) {
214+ GTEST_SKIP ();
215+ }
216+
217+ auto tuple = std::make_shared<ColumnTuple>(std::vector<ColumnRef>({
218+ std::make_shared<ColumnUInt64>(),
219+ std::make_shared<ColumnString>()
220+ }));
221+
222+ if (!createTable (tuple)) {
223+ GTEST_SKIP ();
224+ }
225+
226+ client_->Execute (" INSERT INTO " + table_name +
227+ " SELECT number, "
228+ " (if (number % 10 = 0, number, 0), repeat('a', number % 10 + 1))"
229+ " FROM numbers(1000);" );
230+
231+ client_->Select (getOneColumnSelectQuery (),
232+ [&](const Block& block) {
233+ // std::cerr << PrettyPrintBlock{block} << std::endl;
234+ if (block.GetRowCount () == 0 )
235+ return ;
236+ EXPECT_EQ (1000u , block.GetRowCount ());
237+ ASSERT_EQ (1U , block.GetColumnCount ());
238+ auto cl = block[0 ]->AsStrict <ColumnTuple>();
239+ ASSERT_EQ (2U , cl->TupleSize ());
240+ EXPECT_EQ ((*cl)[0 ]->GetSerialization ()->GetKind (), Serialization::Kind::SPARSE);
241+ EXPECT_EQ ((*cl)[1 ]->GetSerialization ()->GetKind (), Serialization::Kind::DEFAULT);
242+ auto cl_int = (*cl)[0 ]->AsStrict <ColumnUInt64>();
243+ for (size_t i = 0 ; i < 1000 ; ++i) {
244+ if (i % 10 == 0 ) {
245+ EXPECT_EQ (cl_int->At (i), i);
246+ } else {
247+ EXPECT_EQ (cl_int->At (i), 0u );
248+ }
249+ }
250+ });
108251}
0 commit comments