ClickHouse / ClickHouse/clickhouse-cs

Types: Object('json') column is parsed as SimpleAggregateFunction, so GetSchema("Columns") reports "SimpleAggregateFunction(, Json)"

Open Beginner friendly
#545 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
C#
Stars
94
Forks
22
Avg merge
11h 26m
Merged PRs (30d)
22

Description

### Describe the bug

`ObjectType.Parse` builds and returns a `SimpleAggregateFunctionType` instead of an `ObjectType`
(`ClickHouse.Driver/Types/ObjectType.cs:16-22`):

```csharp
public override ParameterizedType Parse(SyntaxTreeNode node, Func parseClickHouseTypeFunc, TypeSettings settings)
{
return new SimpleAggregateFunctionType
{
UnderlyingType = parseClickHouseTypeFunc(node.ChildNodes[0]),
};
}
```

Every other `ParameterizedType.Parse` returns its own type. As a result a column whose server type is
`Object('json')` resolves to a `SimpleAggregateFunctionType` whose `AggregateFunction` is `null`, so
its rendered name is `SimpleAggregateFunction(, Json)`.

This is user-visible through `GetSchema("Columns")`, which reads `system.columns.type` and runs it
through `TypeConverter.ParseClickHouseType`, then reports `clickHouseType.ToString()` as
`ProviderType` (`ClickHouse.Driver/Utility/SchemaDescriber.cs:128-133`).

Two side effects of the same defect:

* `ObjectType`'s own members (`Name`, `ToString`, `Read`, `Write`) are unreachable — no code path can
ever produce an `ObjectType` instance.
* The alias `{ "OBJECT('JSON')", "Json" }` (`TypeConverter.cs:95`) is dead. `ExtractTypeName` looks up
the alias table with the parsed node value, which for `Object('json')` is just `Object`, so the
parenthesised alias key never matches and the intended mapping to `Json` never happens.

Data reads are not corrupted: `SimpleAggregateFunctionType.Read/Write` delegate to `UnderlyingType`,
which is the same type `ObjectType` would have delegated to. The defect is in the reported type
identity, not in the values.

### Steps to reproduce

1. Start a ClickHouse 25.8 server with `allow_experimental_object_type=1`.
2. `CREATE TABLE zz_probe (id Int32, o Object('json')) ENGINE=Memory`
3. Call `connection.GetSchema("Columns", new[] { "default", "zz_probe" })` and read `ProviderType`.

### Expected behaviour

The reported type should identify the column as an `Object`/`Json` column, not as a
`SimpleAggregateFunction`. The server reports it as `Object('json')`:

```
$ curl -s 'http://server:8123/' --data-binary "SELECT name, type FROM system.columns WHERE table='zz_probe' FORMAT TSV"
id Int32
o Object(\'json\')
```

The alias table already states the intent for this type (`OBJECT('JSON')` -> `Json`), so resolving it
to `SimpleAggregateFunction` is clearly unintended.

### Code example

```csharp
using var conn = new ClickHouseConnection("Host=server;Port=8123;Username=default;Compression=false");
conn.CustomSettings.Add("allow_experimental_object_type", 1);
await conn.ExecuteStatementAsync("CREATE TABLE zz_probe (id Int32, o Object('json')) ENGINE=Memory");

var schema = conn.GetSchema("Columns", new[] { "default", "zz_probe" });
foreach (DataRow r in schema.Rows)
Console.WriteLine($"{r["Name"]} => ProviderType='{r["ProviderType"]}'");
```

Actual output:

```
id => ProviderType='Int32'
o => ProviderType='SimpleAggregateFunction(, Json)'
```

Parsing the type string directly shows the same result for every `Object(...)` shape:

```
INPUT=Object('json') -> CLR=SimpleAggregateFunctionType ToString=SimpleAggregateFunction(, Json)
INPUT=Object(String) -> CLR=SimpleAggregateFunctionType ToString=SimpleAggregateFunction(, String)
INPUT=Object(Nullable(String)) -> CLR=SimpleAggregateFunctionType ToString=SimpleAggregateFunction(, Nullable(String))
```

Contrast case that must keep its current behaviour:

```
INPUT=SimpleAggregateFunction(sum, Int64) -> ToString=SimpleAggregateFunction(sum, Int64) (correct)
```

### Error log

No exception. The type is silently reported under the wrong name.

### Root cause

`ClickHouse.Driver/Types/ObjectType.cs:16-22` — `Parse` returns a `SimpleAggregateFunctionType`
rather than an `ObjectType`. Because `SimpleAggregateFunctionType.Parse` expects two child nodes
(`AggregateFunction`, `UnderlyingType`) while `Object(...)` has one, the produced instance also has a
`null` `AggregateFunction`, which is what renders as the empty first argument.

### Suggested fix

Return the type the class represents:

```csharp
return new ObjectType
{
UnderlyingType = parseClickHouseTypeFunc(node.ChildNodes[0]),
};
```

If, instead, `Object('json')` is meant to be an alias of `Json` (which the `OBJECT('JSON')` alias
entry suggests), then the alias lookup should be made to actually fire and the intent documented —
but either way it should not resolve to a third, unrelated type. `SimpleAggregateFunction(...)`
parsing must keep its current behaviour.

### Configuration
#### Environment
* Client version: `main` (commit at the time of testing), built for `net10.0`
* .NET version: .NET 10.0 SDK
* OS: Linux (Debian container)

#### ClickHouse server
* ClickHouse Server version: 25.8.28.1 (the repo's supported floor; the type still exists there).
Note: on 26.7 the server has removed `Object(...)` entirely (`Unknown data type family: Object`),
so this only affects servers that still accept the deprecated type.
* ClickHouse Server non-default settings: `allow_experimental_object_type=1`
* `CREATE TABLE`: `CREATE TABLE zz_probe (id Int32, o Object('json')) ENGINE=Memory`

---

Found by automated analysis of this client while working on #542 / PR #544, and verified against a
live 25.8 server rather than by inspection.

Contributor guide

Open the contributing guide

Research direction

Start in ClickHouse.Driver/Types/ObjectType.cs:16-22 and inspect how ObjectType.Parse constructs the parsed type. Reproduce the examples through TypeConverter.ParseClickHouseType or GetSchema("Columns"), then verify Object(...) reports its intended type while SimpleAggregateFunction(sum, Int64) remains unchanged; SchemaDescriber.cs:128-133 shows the reported ProviderType path.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, sql
Domain
databases
Issue type
Bug
Difficulty
1/5
Estimated time
Under an hour
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
85/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.