Describe the bug
ObjectType.Parse builds and returns a SimpleAggregateFunctionType instead of an ObjectType
(ClickHouse.Driver/Types/ObjectType.cs:16-22):
public override ParameterizedType Parse(SyntaxTreeNode node, Func<SyntaxTreeNode, ClickHouseType> 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
- Start a ClickHouse 25.8 server with
allow_experimental_object_type=1.
CREATE TABLE zz_probe (id Int32, o Object('json')) ENGINE=Memory
- 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
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:
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.
Describe the bug
ObjectType.Parsebuilds and returns aSimpleAggregateFunctionTypeinstead of anObjectType(
ClickHouse.Driver/Types/ObjectType.cs:16-22):Every other
ParameterizedType.Parsereturns its own type. As a result a column whose server type isObject('json')resolves to aSimpleAggregateFunctionTypewhoseAggregateFunctionisnull, soits rendered name is
SimpleAggregateFunction(, Json).This is user-visible through
GetSchema("Columns"), which readssystem.columns.typeand runs itthrough
TypeConverter.ParseClickHouseType, then reportsclickHouseType.ToString()asProviderType(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 canever produce an
ObjectTypeinstance.{ "OBJECT('JSON')", "Json" }(TypeConverter.cs:95) is dead.ExtractTypeNamelooks upthe alias table with the parsed node value, which for
Object('json')is justObject, so theparenthesised alias key never matches and the intended mapping to
Jsonnever happens.Data reads are not corrupted:
SimpleAggregateFunctionType.Read/Writedelegate toUnderlyingType,which is the same type
ObjectTypewould have delegated to. The defect is in the reported typeidentity, not in the values.
Steps to reproduce
allow_experimental_object_type=1.CREATE TABLE zz_probe (id Int32, o Object('json')) ENGINE=Memoryconnection.GetSchema("Columns", new[] { "default", "zz_probe" })and readProviderType.Expected behaviour
The reported type should identify the column as an
Object/Jsoncolumn, not as aSimpleAggregateFunction. The server reports it asObject('json'):The alias table already states the intent for this type (
OBJECT('JSON')->Json), so resolving itto
SimpleAggregateFunctionis clearly unintended.Code example
Actual output:
Parsing the type string directly shows the same result for every
Object(...)shape:Contrast case that must keep its current behaviour:
Error log
No exception. The type is silently reported under the wrong name.
Root cause
ClickHouse.Driver/Types/ObjectType.cs:16-22—Parsereturns aSimpleAggregateFunctionTyperather than an
ObjectType. BecauseSimpleAggregateFunctionType.Parseexpects two child nodes(
AggregateFunction,UnderlyingType) whileObject(...)has one, the produced instance also has anullAggregateFunction, which is what renders as the empty first argument.Suggested fix
Return the type the class represents:
If, instead,
Object('json')is meant to be an alias ofJson(which theOBJECT('JSON')aliasentry 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
main(commit at the time of testing), built fornet10.0ClickHouse server
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.
allow_experimental_object_type=1CREATE TABLE:CREATE TABLE zz_probe (id Int32, o Object('json')) ENGINE=MemoryFound by automated analysis of this client while working on #542 / PR #544, and verified against a
live 25.8 server rather than by inspection.