#include #include #include "clickhouse/columns/nullable.h" #include "clickhouse/columns/lowcardinality.h" #include "clickhouse/client.h" #include "utils.h" #include "clickhouse/base/wire_format.h" #include namespace { using namespace clickhouse; } static const auto localHostEndpoint = ClientOptions() .SetHost( getEnvOrDefault("CLICKHOUSE_HOST", "localhost")) .SetPort( getEnvOrDefault("CLICKHOUSE_PORT", "9000")) .SetUser( getEnvOrDefault("CLICKHOUSE_USER", "default")) .SetPassword( getEnvOrDefault("CLICKHOUSE_PASSWORD", "")) .SetDefaultDatabase(getEnvOrDefault("CLICKHOUSE_DB", "default")); ColumnRef buildTestColumn(const std::vector& rowsData, const std::vector& nulls) { auto stringColumn = std::make_shared(rowsData); auto nullsColumn = std::make_shared(nulls); auto lowCardinalityColumn = std::make_shared( std::make_shared(stringColumn, nullsColumn) ); return lowCardinalityColumn; } void createTable(Client& client) { client.Execute("DROP TEMPORARY TABLE IF EXISTS lc_of_nullable"); client.Execute("CREATE TEMPORARY TABLE IF NOT EXISTS lc_of_nullable (words LowCardinality(Nullable(String))) ENGINE = Memory"); } TEST(LowCardinalityOfNullable, InsertAndQuery) { const auto rowsData = std::vector { "eminem", "", "tupac", "shady", "fifty", "dre", "", "cube" }; const auto nulls = std::vector { false, false, true, false, true, true, false, false }; auto column = buildTestColumn(rowsData, nulls); Block block; block.AppendColumn("words", column); Client client(ClientOptions(localHostEndpoint) .SetBakcwardCompatibilityFeatureLowCardinalityAsWrappedColumn(false) .SetPingBeforeQuery(true)); createTable(client); client.Insert("lc_of_nullable", block); client.Select("SELECT * FROM lc_of_nullable", [&](const Block& bl) { for (size_t row = 0; row < bl.GetRowCount(); row++) { auto lc_col = bl[0]->As(); auto item = lc_col->GetItem(row); if (nulls[row]) { ASSERT_EQ(Type::Code::Void, item.type); } else { ASSERT_EQ(rowsData[row], item.get()); } } }); } TEST(LowCardinalityOfNullable, InsertAndQueryOneRow) { const auto rowsData = std::vector { "eminem" }; const auto nulls = std::vector { false }; auto column = buildTestColumn(rowsData, nulls); Block block; block.AppendColumn("words", column); Client client(ClientOptions(localHostEndpoint) .SetBakcwardCompatibilityFeatureLowCardinalityAsWrappedColumn(false) .SetPingBeforeQuery(true)); createTable(client); client.Insert("lc_of_nullable", block); client.Select("SELECT * FROM lc_of_nullable", [&](const Block& bl) { for (size_t row = 0; row < bl.GetRowCount(); row++) { auto lc_col = bl[0]->As(); auto item = lc_col->GetItem(row); if (nulls[row]) { ASSERT_EQ(Type::Code::Void, item.type); } else { ASSERT_EQ(rowsData[row], item.get()); } } }); } TEST(LowCardinalityOfNullable, InsertAndQueryEmpty) { auto column = buildTestColumn({}, {}); Block block; block.AppendColumn("words", column); Client client(ClientOptions(localHostEndpoint) .SetBakcwardCompatibilityFeatureLowCardinalityAsWrappedColumn(false) .SetPingBeforeQuery(true)); createTable(client); EXPECT_NO_THROW(client.Insert("lc_of_nullable", block)); client.Select("SELECT * FROM lc_of_nullable", [&](const Block& bl) { ASSERT_EQ(bl.GetRowCount(), 0u); }); } TEST(LowCardinalityOfNullable, DISABLED_ThrowOnBackwardsCompatibleLCColumn) { auto column = buildTestColumn({}, {}); Block block; block.AppendColumn("words", column); Client client(ClientOptions(localHostEndpoint) .SetPingBeforeQuery(true) .SetBakcwardCompatibilityFeatureLowCardinalityAsWrappedColumn(true)); createTable(client); EXPECT_THROW(client.Insert("lc_of_nullable", block), UnimplementedError); client.Select("SELECT * FROM lc_of_nullable", [&](const Block& bl) { ASSERT_EQ(bl.GetRowCount(), 0u); }); }