使用JDBC预编译语句向ClickHouse插入DateTime64字段报解析错误的原因排查
异常核心原因
这个问题是ClickHouse旧版JDBC驱动的批量插入实现逻辑和常规SQL执行逻辑不匹配导致的,具体拆解:
- 预期执行逻辑
你在SQL中写入parseDateTime64BestEffort(:time_stamp),是希望ClickHouse服务端接收到完整SQL后,由服务端执行这个时间解析函数,把传入的带时区偏移的时间字符串,转换成符合表结构要求的DateTime64(3, 'Europe/Moscow')类型值。 - 实际驱动执行逻辑
你使用的ru.yandex.clickhouse包的旧版ClickHouse JDBC驱动,批量插入时并不会把整条带函数表达式的SQL下发给服务端解析:- 驱动会在客户端本地解析SQL中声明的目标列清单,把所有绑定的参数值按列顺序,拼接成ClickHouse原生批量接收的、用制表符分隔字段、换行符分隔行的TSV格式数据流,直接推送给服务端的批量插入接口。
- 这种模式下,你写在VALUES子句里的函数调用会被驱动直接忽略,根本不会传递到服务端执行,每个列的值都会直接取你绑定的原始参数值。
- 报错触发的直接环节
你传入的time_stamp参数是带时区后缀的字符串2021-04-02T17:22:32.999+03:00,这个原始值被直接放入time_stamp列的输入流中。而ClickHouse对DateTime64类型的纯字符串直接输入,默认只会解析到标准时间格式的核心部分2021-04-02T17:22:32.999就停止,后面的+03:00不属于合法的DateTime64格式字符,就被错误识别为下一列user_id的内容,最终因为字段分隔位置不符合预期抛出代码27的解析错误。
手动执行无报错的原因
在控制台手动执行SQL时,整条包含函数调用的SQL文本会完整传递给ClickHouse服务端,服务端的SQL解析器会正常执行parseDateTime64BestEffort函数完成时间格式转换,因此不会触发解析错误。
内容的提问来源于stack exchange,提问作者Roman Patrushev
相关产品推荐
相关产品推荐

