@@ -1823,6 +1823,117 @@ const auto LocalHostEndpoint = ClientOptions()
18231823 .SetPassword( getEnvOrDefault(" CLICKHOUSE_PASSWORD" , " " ))
18241824 .SetDefaultDatabase(getEnvOrDefault(" CLICKHOUSE_DB" , " default" ));
18251825
1826+ namespace {
1827+
1828+ using KeyValuePairs = std::vector<std::pair<std::string, uint8_t >>;
1829+
1830+ KeyValuePairs KeyValuePairsOf (const ColumnRef& column) {
1831+ auto tuples = column->AsStrict <ColumnTuple>();
1832+ auto keys = (*tuples)[0 ]->AsStrict <ColumnString>();
1833+ auto values = (*tuples)[1 ]->AsStrict <ColumnUInt8>();
1834+ KeyValuePairs pairs;
1835+ for (size_t i = 0 ; i < tuples->Size (); ++i) {
1836+ pairs.emplace_back (std::string (keys->At (i)), values->At (i));
1837+ }
1838+ return pairs;
1839+ }
1840+
1841+ std::vector<KeyValuePairs> ArraysOfKeyValuePairsOf (const ColumnRef& column) {
1842+ auto arrays = column->AsStrict <ColumnArray>();
1843+ std::vector<KeyValuePairs> arrays_of_pairs;
1844+ for (size_t i = 0 ; i < arrays->Size (); ++i) {
1845+ arrays_of_pairs.push_back (KeyValuePairsOf (arrays->GetAsColumn (i)));
1846+ }
1847+ return arrays_of_pairs;
1848+ }
1849+
1850+ }
1851+
1852+ TEST_P (ClientCase, ArrayOfNested_SelectServerTypedColumn) {
1853+ client_->Execute (" DROP TEMPORARY TABLE IF EXISTS test_clickhouse_cpp_array_of_nested" );
1854+ client_->Execute (" CREATE TEMPORARY TABLE test_clickhouse_cpp_array_of_nested "
1855+ " (id UInt8, arrays_of_pairs Array(Nested(key String, value UInt8)))" );
1856+ client_->Execute (" INSERT INTO test_clickhouse_cpp_array_of_nested VALUES "
1857+ " (1, [[('a', 1), ('b', 2)], []]), (2, []), (3, [[('c', 3)]])" );
1858+
1859+ std::vector<std::vector<KeyValuePairs>> rows;
1860+ std::string type_name;
1861+ client_->Select (" SELECT id, arrays_of_pairs FROM test_clickhouse_cpp_array_of_nested ORDER BY id" , [&](const Block& block) {
1862+ if (block.GetRowCount () == 0 ) {
1863+ return ;
1864+ }
1865+ type_name = block[1 ]->GetType ().GetName ();
1866+ auto arrays_of_pairs = block[1 ]->AsStrict <ColumnArray>();
1867+ for (size_t row = 0 ; row < block.GetRowCount (); ++row) {
1868+ rows.push_back (ArraysOfKeyValuePairsOf (arrays_of_pairs->GetAsColumn (row)));
1869+ }
1870+ });
1871+
1872+ EXPECT_EQ (" Array(Array(Tuple(key String, value UInt8)))" , type_name);
1873+ const std::vector<std::vector<KeyValuePairs>> expected = {
1874+ {{{" a" , 1 }, {" b" , 2 }}, {}},
1875+ {},
1876+ {{{" c" , 3 }}},
1877+ };
1878+ EXPECT_EQ (expected, rows);
1879+ }
1880+
1881+ TEST_P (ClientCase, ArrayOfNested_ReinsertSelectedRows) {
1882+ client_->Execute (" DROP TEMPORARY TABLE IF EXISTS test_clickhouse_cpp_array_of_nested_source" );
1883+ client_->Execute (" DROP TEMPORARY TABLE IF EXISTS test_clickhouse_cpp_array_of_nested_copy" );
1884+ client_->Execute (" CREATE TEMPORARY TABLE test_clickhouse_cpp_array_of_nested_source "
1885+ " (id UInt8, arrays_of_pairs Array(Nested(key String, value UInt8)))" );
1886+ client_->Execute (" CREATE TEMPORARY TABLE test_clickhouse_cpp_array_of_nested_copy "
1887+ " (id UInt8, arrays_of_pairs Array(Nested(key String, value UInt8)))" );
1888+ client_->Execute (" INSERT INTO test_clickhouse_cpp_array_of_nested_source VALUES (1, [[('a', 1), ('b', 2)], []]), (2, [])" );
1889+
1890+ std::vector<Block> selected_blocks;
1891+ client_->Select (" SELECT id, arrays_of_pairs FROM test_clickhouse_cpp_array_of_nested_source ORDER BY id" , [&](const Block& block) {
1892+ if (block.GetRowCount () > 0 ) {
1893+ selected_blocks.push_back (block);
1894+ }
1895+ });
1896+ for (const auto & block : selected_blocks) {
1897+ client_->Insert (" test_clickhouse_cpp_array_of_nested_copy" , block);
1898+ }
1899+
1900+ std::vector<std::string> rendered_rows;
1901+ client_->Select (" SELECT toString(arrays_of_pairs) FROM test_clickhouse_cpp_array_of_nested_copy ORDER BY id" ,
1902+ [&](const Block& block) {
1903+ for (size_t row = 0 ; row < block.GetRowCount (); ++row) {
1904+ rendered_rows.emplace_back (block[0 ]->AsStrict <ColumnString>()->At (row));
1905+ }
1906+ });
1907+
1908+ const std::vector<std::string> expected = {" [[('a',1),('b',2)],[]]" , " []" };
1909+ EXPECT_EQ (expected, rendered_rows);
1910+ }
1911+
1912+ TEST_P (ClientCase, Nested_UnflattenedColumn) {
1913+ client_->Execute (" SET flatten_nested = 0" );
1914+ client_->Execute (" DROP TEMPORARY TABLE IF EXISTS test_clickhouse_cpp_nested_unflattened" );
1915+ client_->Execute (" CREATE TEMPORARY TABLE test_clickhouse_cpp_nested_unflattened "
1916+ " (id UInt8, pairs Nested(key String, value UInt8))" );
1917+ client_->Execute (" INSERT INTO test_clickhouse_cpp_nested_unflattened VALUES (1, [('a', 1), ('b', 2)]), (2, [])" );
1918+
1919+ std::vector<KeyValuePairs> rows;
1920+ std::string type_name;
1921+ client_->Select (" SELECT id, pairs FROM test_clickhouse_cpp_nested_unflattened ORDER BY id" , [&](const Block& block) {
1922+ if (block.GetRowCount () == 0 ) {
1923+ return ;
1924+ }
1925+ type_name = block[1 ]->GetType ().GetName ();
1926+ auto pairs = block[1 ]->AsStrict <ColumnArray>();
1927+ for (size_t row = 0 ; row < block.GetRowCount (); ++row) {
1928+ rows.push_back (KeyValuePairsOf (pairs->GetAsColumn (row)));
1929+ }
1930+ });
1931+
1932+ EXPECT_EQ (" Array(Tuple(key String, value UInt8))" , type_name);
1933+ const std::vector<KeyValuePairs> expected = {{{" a" , 1 }, {" b" , 2 }}, {}};
1934+ EXPECT_EQ (expected, rows);
1935+ }
1936+
18261937INSTANTIATE_TEST_SUITE_P (
18271938 Client, ClientCase,
18281939 ::testing::Values (
0 commit comments