Skip to content

JSON typed path containing a space is unparseable: unsupported column type "b` Int64" #1948

Description

@claude

Describe the bug

ClickHouse allows a JSON typed path name to contain characters that require backtick quoting, e.g. a space. The server accepts, stores and round-trips JSON(a b Int64) fine, but this driver cannot parse the column type at all, so the whole query fails — not just the offending path.

In lib/column/json.go, (*JSON).parse splits each type part on the first space:

https://github.com/ClickHouse/clickhouse-go/blob/main/lib/column/json.go#L137-L143

typedPathParts := strings.SplitN(typePart, " ", 2)
if len(typedPathParts) != 2 {
    continue
}

typedPath := strings.Trim(typedPathParts[0], "`")
typeName := strings.TrimSpace(typedPathParts[1])

For the type part `a b` Int64 this yields typedPath = "a" and typeName = "b Int64", and the subsequent Type(typeName).Column(...)` call fails.

Note that the sibling helper splitWithDelimiters (json.go:1084) is backtick-aware, so the comma case (JSON(`a,b` Int64)) works correctly — only the space split is wrong. Dotted paths are fine too (both sides treat . as a nesting separator).

ClickHouse server version

Code analysis plus a driver-side unit test; no ClickHouse server was reachable in this environment, so this was not verified end-to-end against a live server. The type strings used in the test are the forms the server emits (as reported in the linked upstream issue, measured against ClickHouse 26.6.1).

Reproduction

Drop this into lib/column/ and run go test ./lib/column/ -run TestJSONPathWithSpace -v:

package column

import "testing"

func TestJSONPathWithSpace(t *testing.T) {
	types := []string{
		"JSON(`a b` Int64)",
		"JSON(`a b` Decimal(10, 2))",
		"JSON(`a,b` Int64)",
		"JSON(`a.b` Int64)",
	}
	for _, tStr := range types {
		col, err := Type(tStr).Column("x", nil)
		if err != nil {
			t.Errorf("%s -> ERROR %v", tStr, err)
			continue
		}
		t.Logf("%s -> typedPaths=%v", tStr, col.(*JSON).typedPaths)
	}
}

Expected: all four parse, with typedPaths of [a b], [a b], [a,b], [a.b].

Actual (run on main):

    json_space_test.go:15: JSON(`a b` Int64) -> ERROR failed to init column of type "b` Int64" at path "a": clickhouse: unsupported column type "b` Int64"
    json_space_test.go:15: JSON(`a b` Decimal(10, 2)) -> ERROR failed to init column of type "b` Decimal(10, 2)" at path "a": clickhouse: unsupported column type "b` Decimal(10, 2)"
    json_space_test.go:19: JSON(`a,b` Int64) -> typedPaths=[a,b]
    json_space_test.go:19: JSON(`a.b` Int64) -> typedPaths=[a.b]
--- FAIL: TestJSONPathWithSpace (0.00s)

The equivalent end-to-end usage that would hit this:

CREATE TABLE t (data JSON(`a b` Int64)) ENGINE = Memory;
INSERT INTO t VALUES ('{"a b": 1}');
rows, err := conn.Query(ctx, "SELECT data FROM t")
// column-type parsing of the response header fails, so Query itself errors

Also note the path is silently mis-registered as "a" before the type parse fails, so any future leniency here would need to fix both halves.

Suggested fix

lib/column/json.go:137 — split the typed-path part on the last space that is outside backticks, rather than on the first space, mirroring the backtick awareness already present in splitWithDelimiters. The path is already strings.Trim(..., "")`-ed on the next line, so backtick-quoted names are clearly intended to be supported here.

Link

Relayed from ClickHouse/clickhouse-cs#502 (same root cause, different split bug: the C# driver splits on every space).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions