Skip to content

Don't copy the type AST at every LowCardinality level - #588

Merged
slabko merged 1 commit into
ClickHouse:masterfrom
iliaal:fix/lowcardinality-ast-copy
Oct 22, 2026
Merged

slabko merged 1 commit into
ClickHouse:masterfrom
iliaal:fix/lowcardinality-ast-copy

Conversation

@iliaal

@iliaal iliaal commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

CreateColumnFromAst in columns/factory.cpp binds the LowCardinality child with const auto nested = GetASTChildElement(ast, 0);, which deep-copies the whole subtree at every level. All the copies stay alive down the recursion, so memory grows with depth × width. A ~110 KB type string, LowCardinality(Nullable( nested about 250 times over a Tuple of a few thousand UInt8, makes the client allocate hundreds of megabytes before it reports the type as unsupported. A server can send such a type in a block header.

Fix: bind the child by const reference. It was the only by-value copy of the AST on a recursive path in factory.cpp.

Test: CreateColumnByType.NestedLowCardinalityDoesNotCopyAst builds 200 levels over Tuple(UInt8 × 8000) and checks that peak RSS grows by less than 16 MiB. On master it grows by about 220 MiB, in the full test binary too; with the fix, about 5 MiB. It reads /proc/self/status, so it runs on Linux only and skips elsewhere. The include reorder in that test file comes from clang-format's include regrouping.

CreateColumnFromAst() binds the LowCardinality child as
"const auto nested = GetASTChildElement(ast, 0)", which copies the whole
subtree. With nested LowCardinality(Nullable(...)) levels every level
makes another copy while the recursion still holds the earlier ones, so
peak memory grows with depth times subtree width: 200 levels over an
8000-element Tuple took about 220 MiB before the type was rejected. Bind
the child by reference instead.
@slabko
slabko merged commit 85aa74b into ClickHouse:master Oct 22, 2026
44 of 45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants