Skip to content

Fix ClickHouse LowCardinality + Nullable wrapping order#14

Merged
lohanidamodar merged 1 commit into
mainfrom
fix/clickhouse-lowcardinality-nullable-order
Jul 6, 2026
Merged

Fix ClickHouse LowCardinality + Nullable wrapping order#14
lohanidamodar merged 1 commit into
mainfrom
fix/clickhouse-lowcardinality-nullable-order

Conversation

@lohanidamodar

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes the wrapping order the ClickHouse schema compiler emits when a column is both lowCardinality() and nullable().

Bug: the compiler emitted Nullable(LowCardinality(String)), which ClickHouse rejects with ILLEGAL_TYPE_OF_ARGUMENT (verified against clickhouse-server 25.11), so any schema declaring ->lowCardinality()->nullable() fails to create. The valid form is LowCardinality(Nullable(String))LowCardinality must be the outermost wrapper.

Fix: in compileColumnType(), apply Nullable(...) before LowCardinality(...) in both the FixedString branch and the scalar type branch, so LowCardinality always wraps outermost. Docblock and README examples updated to match.

Tests:

  • Updated the existing combined-wrapper test to assert LowCardinality(Nullable(String))
  • Added a FixedString variant asserting LowCardinality(Nullable(FixedString(2)))
  • Existing lowCardinality-only and nullable-only coverage unchanged

Note for #13 (feat/clickhouse-nested-column-quoting): its consumers (utopia-php/audit#120, utopia-php/usage#4) hit this bug, so #13 should rebase on or merge this fix once it lands.

Test Plan

  • composer test — 5267 tests, 12224 assertions, OK
  • composer lint — pass
  • composer check — PHPStan level max, no errors

Related PRs and Issues

ClickHouse rejects Nullable(LowCardinality(String)) with
ILLEGAL_TYPE_OF_ARGUMENT. The valid form wraps LowCardinality
outermost: LowCardinality(Nullable(String)). Apply Nullable before
LowCardinality in both the FixedString and scalar type branches of
the schema compiler, and update the docs accordingly.
@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Fixes the LowCardinality/Nullable wrapping order emitted by the ClickHouse schema compiler, which previously produced the invalid Nullable(LowCardinality(T)) form that ClickHouse rejects at DDL time.

  • src/Query/Schema/ClickHouse.php: In compileColumnType(), Nullable(...) is now applied before LowCardinality(...) in both the FixedString branch and the scalar-type branch, so the output is always the valid LowCardinality(Nullable(T)).
  • Tests: The existing combined-wrapper assertion is corrected and a new FixedString variant (LowCardinality(Nullable(FixedString(2)))) is added; single-modifier paths are untouched.
  • README + docblock: Updated to reflect the correct wrapping order and prose description.

Confidence Score: 5/5

Safe to merge — the change is a two-line reorder in each of two code paths, both covered by targeted tests that assert the now-valid ClickHouse DDL output.

The fix is minimal and well-scoped: it reorders four conditional blocks so LowCardinality always wraps outermost. Both affected branches (FixedString and scalar) are independently exercised in new and updated tests. The only observable behavior change is producing DDL that ClickHouse actually accepts. Existing single-modifier paths (nullable-only, lowCardinality-only) are not touched and their tests remain green.

No files require special attention.

Important Files Changed

Filename Overview
src/Query/Schema/ClickHouse.php Swaps Nullable/LowCardinality application order in both the FixedString branch and the scalar branch so LowCardinality always wraps outermost, matching ClickHouse's type constraint
src/Query/Schema/Column/ClickHouse.php Docblock updated to reflect corrected wrapping order (LowCardinality(Nullable(String)))
tests/Query/Schema/ClickHouseTest.php Existing combined-wrapper test updated and a new FixedString variant added to assert correct LowCardinality(Nullable(...)) form
README.md Comment block corrected to show LowCardinality(Nullable(String)) and prose updated to say Nullable is applied inside LowCardinality

Reviews (1): Last reviewed commit: "Fix ClickHouse LowCardinality + Nullable..." | Re-trigger Greptile

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

📊 Coverage

Metric Covered Ratio
Lines 91.81% 7408 / 8069
Methods 84.42% 1100 / 1303
Classes 65.85% 135 / 205

Full per-file breakdown in the job summary.

@lohanidamodar lohanidamodar merged commit 0ffa242 into main Jul 6, 2026
7 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.

1 participant