Skip to content

Conversation

@Cyanty
Copy link
Contributor

@Cyanty Cyanty commented Sep 28, 2025

close #9857

Issue:
When using clickhouse-client:0.3.2-patch11, inserting data into a JSON column throws an Unsupported data type exception. The error originates from ClickHouseRowBinaryProcessor#MappedFunctions.serialize(484).

Root Cause:
The ClickHouseRowBinaryProcessor in this driver version lacks a serializer mapping for the JSON data type. For INSERT ... VALUES (?,?,...) statements, the driver defaults to using InputBasedPreparedStatement, which invokes the serialize method during addBatch(). This inevitably triggers the exception when a JSON type is encountered.

Solution:
It was observed that if the VALUES() clause contains characters other than ?, ,, or Whitespace, the driver defaults to SqlBasedPreparedStatement. This implementation builds the INSERT statement by concatenating values as a single string and does not call the serialize method. By slightly modifying the statement, we can force the use of SqlBasedPreparedStatement, thus bypassing the bug and enabling JSON insertion without a driver update.

Check list


public static final BasicType<String> STRING_TYPE =
new BasicType<>(String.class, SqlType.STRING);
public static final BasicType<String> JSON_TYPE = new BasicType<>(String.class, SqlType.JSON);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already has https://github.com/apache/seatunnel/blob/dev/seatunnel-api/src/main/java/org/apache/seatunnel/api/table/type/CommonOptions.java#L33. So I think we can reuse this option. Not create new type.

Hi @Hisoka-X, thank you for the review.
I see now that BasicType#JSON_TYPE is redundant. ck sink can infer the type from the catalog. I'll remove it in the next commit to allow writing to JSON columns without any config changes.

@zhangshenghang
Copy link
Member

Please also verify in e2e code

@Cyanty
Copy link
Contributor Author

Cyanty commented Sep 29, 2025

Please also verify in e2e code

Thank you for the review, I'll add the e2e test in the next commit.

@github-actions github-actions bot added the e2e label Sep 30, 2025
Copy link
Member

@Hisoka-X Hisoka-X left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tableSchema.get(
fieldNames[i]))
? ClickHouseDataType.JSON.name()
: fieldTypes[i].getSqlType().name())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sqltype is come from SeaTunnel. Why it can used in clickhouse sql directly? We should use ClickhouseTypeConverter to convert.

This comment was marked as outdated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sqltype is come from SeaTunnel. Why it can used in clickhouse sql directly? We should use ClickhouseTypeConverter to convert.

Hi @Hisoka-X , Thank you for your guidance. I'm facing a roadblock and would appreciate your input.
To force SqlBasedPreparedStatement for writing JSON types, I'm adding a CAST in the VALUES() clause. And that all other types are converted to a generic ?.
Since only the JSON type requires special handling, I'd like to skip implementing ClickhouseTypeConverter#convert and instead directly use the data types from tableSchema for the CAST.
e.g.​​,String typeName = tableSchema.getOrDefault(fieldName, ""), Do you think this is feasible?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what do you want to do. Could you share some demo? Thanks.

Copy link
Contributor Author

@Cyanty Cyanty Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what do you want to do. Could you share some demo? Thanks.

Hi @Hisoka-X , Thank you for your reply.
Use the native ClickHouse tableSchema for type mapping in the INSERT sql, instead of using SeaTunnel types. JSON columns are now explicitly cast with CAST(? AS String), all other column types remain as a ? placeholder.
here is the code change:

// Uses ClickHouse table schema to get type names
String[] typeNames =
    Arrays.stream(fieldNames)
          .map(name -> tableSchema.getOrDefault(name, ""))
          .toArray(String[]::new);

The CAST for JSON is a workaround for older clickhouse-jdbc limitations when JSON support was experimental, then this implementation is somewhat informal, and this might require further discussion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Cyanty , I found the same issue in ClickHouse/clickhouse-java#2491. I think the better way is upgrade the clickhouse-jdbc version. Could you try this way? Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Cyanty , I found the same issue in ClickHouse/clickhouse-java#2491. I think the better way is upgrade the clickhouse-jdbc version. Could you try this way? Thanks.

Hi @Hisoka-X , Of course, upgrading the driver version would be more reasonable. I will attempt to upgrade the version and check if there are any incompatible codes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Cyanty !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature][ClickhouseSinkWriter Unsupported data type: JSON

3 participants