Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clickhouse/columns/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ static ColumnRef CreateColumnFromAst(const TypeAst& ast, CreateColumnByTypeSetti
break;
}
case TypeAst::LowCardinality: {
const auto nested = GetASTChildElement(ast, 0);
const auto& nested = GetASTChildElement(ast, 0);
if (settings.low_cardinality_as_wrapped_column) {
switch (nested.code) {
// TODO (nemkov): update this to maximize code reuse.
Expand Down
62 changes: 59 additions & 3 deletions ut/CreateColumnByType_ut.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#include <clickhouse/columns/bool.h>
#include <clickhouse/columns/factory.h>
#include <clickhouse/columns/date.h>
#include <clickhouse/columns/factory.h>
#include <clickhouse/columns/json.h>
#include <clickhouse/columns/lowcardinality.h>
#include <clickhouse/columns/numeric.h>
#include <clickhouse/columns/string.h>
#include <clickhouse/columns/tuple.h>
#include <clickhouse/columns/json.h>

#include <gtest/gtest.h>

#include <fstream>
#include <string>
#include <tuple>

namespace {
Expand Down Expand Up @@ -97,6 +98,61 @@ TEST(CreateColumnByType, LowCardinalityGeneralInnerTypes) {
}
}

#if defined(__linux__)
namespace {
long PeakRssKiB() {
std::ifstream status("/proc/self/status");
std::string line;
while (std::getline(status, line)) {
if (line.rfind("VmHWM:", 0) == 0) {
return std::stol(line.substr(6));
}
}
return -1;
}

bool ResetPeakRss() {
std::ofstream clear_refs("/proc/self/clear_refs");
clear_refs << "5";
clear_refs.close();
return !clear_refs.fail();
}
} // namespace
#endif

TEST(CreateColumnByType, NestedLowCardinalityDoesNotCopyAst) {
#if !defined(__linux__)
GTEST_SKIP() << "peak RSS is read from /proc/self/status";
#else
// Each LowCardinality level used to copy its whole subtree, so peak memory
// grew with depth * width (about 220 MiB here) instead of width.
const size_t depth = 200;
const size_t width = 8000;
std::string type_name;
for (size_t i = 0; i < depth; ++i) {
type_name += "LowCardinality(Nullable(";
}
type_name += "Tuple(UInt8";
for (size_t i = 1; i < width; ++i) {
type_name += ", UInt8";
}
type_name += ")";
type_name.append(2 * depth, ')');

if (!ResetPeakRss() || PeakRssKiB() < 0) {
GTEST_SKIP() << "cannot reset or read peak RSS";
}
const long before = PeakRssKiB();
// Whether this type is supported is not the subject; only the memory used
// while building or rejecting it is.
try {
CreateColumnByType(type_name);
} catch (const std::exception&) {
}
EXPECT_LT(PeakRssKiB() - before, 16 * 1024);
#endif
}

TEST(CreateColumnByType, LowCardinality) {
// In the default (non-wrapped) mode, LowCardinality(String)/LowCardinality(FixedString) map to
// the base ColumnLowCardinality (like Array/Nullable/Tuple/Map do), and the strongly-typed
Expand Down
Loading