首批通过分布式安全可靠测评,为关键业务系统打造
send long data 协议下 OBServer core 在 copy_or_convert_str
更新时间:2026-06-04 09:56
在 OceanBase 数据库 V3.2.3 版本中,默认不开启 SQL_NIO,MySQL 租户上未能完全禁用 send long data 协议,使用时可能会导致 OBServer core 在 copy_or_convert_str。
问题现象
MySQL 租户模式下,某些驱动的部分接口在特定情况下会采用 send long data 协议来流式传输数据(该协议在 OBServer 中需要 SQL_NIO 功能的支持)。比如:
用户使用 JDBC ,在连接串中通过
useServerPrepStmts=true开启了 PS 协议,并在 PS 中调用setNCharaterStream、setNClob、setAsciiStream、setBinaryStream、setCharacterStream、setBlob、setClob这些接口设置值时;用户使用 ODBC,并在 PS 模式下调用
SQLParamData、SQLPutData接口时;链路会采用send long data协议来流式传输数据(该协议在 OBServer 中需要 SQL_NIO 功能的支持);用户调用 mysql-connect-c++ 的
setStrting接口,且 value 值长度超过 256K 时。
在 OBServer 不开启 SQL_NIO 来保证读包顺序的情况下(V3.2.4 以下版本不推荐开启),问题版本 OBServer 可能会因 send long data 协议和 execute 协议的处理顺序不正确而 core。
问题原因
MySQL 协议中,在 JDBC useServerPrepStmts=true 场景下,使用 setNCharaterStream、setNClob、setAsciiStream、setBinaryStream、setCharacterStream、setBlob、setClob 等接口对长数据类型对象(如Blob、Clob、Varchar 等)流式地设置值时,JDBC 会先将这些字节流数据分批通过 SEND_LONG_DATA(24) 指令发送到后端(OBProxy 或 OBServer)。待发送接收完所有的字节流数据后,JDBC 才会真正发送携带参数的 Execute_statement(23) 指令,并在 server 端按照位置标记取出相应数据后执行(使用 ODBC,并在 PS 模式下调用 SQLParamData、SQLPutData 接口也是同理)。所以,send long data 协议包处理的本质是把 execute 协议中的 param_data 信息提前发送。
如果 OBServer 不开启 SQL_NIO,那么就无法保证 send long data 协议和 execute 协议的处理顺序。如果在处理完所有 send long data 之前处理了 execute 协议,OBServer 就会因为数据不完整导致 execute 协议读包错误,进而导致 core。所以在 SQL_NIO 关闭时,OBServer 在监测到 send long data 协议后需要报错 -4007 来避免 execute 协议的执行,然而 send long data 协议本身没办法回包,所以当前做法是在接收到 send long data 协议之后增加标记,从而在 execute 阶段进行报错。但是对于极端情况:send long data 协议一个都没有处理,却先处理了 execute 协议,此时标记没有打上,execute 协议包被错误处理,就引发了 core 。

问题的风险及影响
OBServer core。
影响的版本
OceanBase 数据库 V3.2.3 BP9 (oceanbase-3.2.3.3-109000182023071410) 之前的版本。
注意
- OceanBase 数据库 V3.2.3 版本含 SQL_NIO 功能,但因稳定性等原因只能关闭,关闭后就可能触发该问题。
- OceanBase 数据库 V3.2.4 版本及以上版本默认开启 SQL_NIO 功能,所以只要不手动去关闭,就不会碰到该问题。
解决方法
升级至问题已修复版本。目前已修复的版本包括 OceanBase 数据库企业版 V3.2.3 BP9 (oceanbase-3.2.3.3-109000182023071410) 及之后版本。
规避方式
若使用 JDBC:不要调用
setBlob这些接口,应使用setObject或setString等接口替换。若使用 ODBC:不要调用
SQLParamData、SQLPutData接口,应使用SQLBindParameter直接传完整数据替代。