问题现象
使用 dmPython 连接达梦数据库时,偶尔报错:
但实际上数据库中该表/视图确实存在。将客户端断开重连后,同样的 SQL 可以正常执行,问题消失。该问题是偶发性的,无法稳定复现。
根因分析
核心问题:SET SCHEMA 仅在 cursor 创建时执行一次
Cursor_SetSchema_And_Parsetype()(Cursor.c 第 170-236 行)负责通过 dpi_exec_direct 执行 SET SCHEMA "xxx",但该函数仅在 Cursor_New() 中调用(Cursor.c 第 260 行)。
完整的 SQL 执行路径中,没有任何地方重新设置 schema:
Python: cursor.execute(sql)
→ Cursor_Execute() [Cursor.c:2285]
→ Cursor_Execute_inner() [Cursor.c:2149]
→ Cursor_InternalPrepare() [Cursor.c:650] ← 没有调用 SetSchema
→ dpi_prepare(handle, sql)
→ Cursor_InternalExecDirect() [Cursor.c:706] ← 没有调用 SetSchema
→ dpi_exec_direct(handle, sql)
触发条件:DPI 层透明重连
当底层网络出现超时或闪断时,达梦 DPI 层会在驱动无感知的情况下透明重连:
- TCP 连接断开
- DPI 内部自动
logout → login,建立新会话
- 驱动层的
isConnected 仍为 1,认为连接正常
- 但新会话的当前 schema 已回退为用户的默认 schema,而非业务
SET SCHEMA 指定的 schema
- 后续查询在错误的 schema 下执行 → 报"无效的表或视图名"
次要问题:Ping 重连后也未恢复 schema
Connection_Ping_inner()(Connection.c 第 1041-1116 行)在检测到断连并重连(dpi_logout → dpi_login)后,也没有重新执行 SET SCHEMA。即使显式调用 conn.ping(reconnect=True),schema 仍会丢失。
建议修复
在 Cursor_InternalPrepare() 和 Cursor_InternalExecDirect() 中,于 Cursor_clearDescExecInfo() 之后、dpi_prepare()/dpi_exec_direct() 之前,增加 Cursor_SetSchema_And_Parsetype() 调用:
Cursor.c 第 666 行附近 — Cursor_InternalPrepare():
/* 清理上次的描述和执行信息 */
Cursor_clearDescExecInfo(self, 1);
+ /* 确保 schema 设置正确(DPI 透明重连后可能丢失) */
+ if (Cursor_SetSchema_And_Parsetype(self) < 0)
+ return -1;
// prepare statement
Py_BEGIN_ALLOW_THREADS
status = dpi_unbind_params(self->handle);
status = dpi_prepare(self->handle, (sdbyte*)statementBuffer.ptr);
Py_END_ALLOW_THREADS
Cursor.c 第 720 行附近 — Cursor_InternalExecDirect():
/* 清理上次的描述和执行信息 */
Cursor_clearDescExecInfo(self, 1);
+ /* 确保 schema 设置正确(DPI 透明重连后可能丢失) */
+ if (Cursor_SetSchema_And_Parsetype(self) < 0)
+ return -1;
// execute directly
Py_BEGIN_ALLOW_THREADS
status = dpi_exec_direct(self->handle, (sdbyte*)statementBuffer.ptr);
Py_END_ALLOW_THREADS
为什么只改这两处就够了:
prepare 和 exec_direct 是所有 SQL 操作的必经路径(查询/插入/更新/DDL 都走这里)
Connection_Ping_inner 重连后,下一次 execute 自然会触发 schema 恢复
- DPI 透明重连后,同理
Cursor_SetSchema_And_Parsetype() 内部已判断:若 connection->schema 为 None 则直接返回 0,零额外开销
问题现象
使用 dmPython 连接达梦数据库时,偶尔报错:
但实际上数据库中该表/视图确实存在。将客户端断开重连后,同样的 SQL 可以正常执行,问题消失。该问题是偶发性的,无法稳定复现。
根因分析
核心问题:SET SCHEMA 仅在 cursor 创建时执行一次
Cursor_SetSchema_And_Parsetype()(Cursor.c第 170-236 行)负责通过dpi_exec_direct执行SET SCHEMA "xxx",但该函数仅在Cursor_New()中调用(Cursor.c第 260 行)。完整的 SQL 执行路径中,没有任何地方重新设置 schema:
触发条件:DPI 层透明重连
当底层网络出现超时或闪断时,达梦 DPI 层会在驱动无感知的情况下透明重连:
logout→login,建立新会话isConnected仍为1,认为连接正常SET SCHEMA指定的 schema次要问题:Ping 重连后也未恢复 schema
Connection_Ping_inner()(Connection.c第 1041-1116 行)在检测到断连并重连(dpi_logout→dpi_login)后,也没有重新执行SET SCHEMA。即使显式调用conn.ping(reconnect=True),schema 仍会丢失。建议修复
在
Cursor_InternalPrepare()和Cursor_InternalExecDirect()中,于Cursor_clearDescExecInfo()之后、dpi_prepare()/dpi_exec_direct()之前,增加Cursor_SetSchema_And_Parsetype()调用:Cursor.c第 666 行附近 —Cursor_InternalPrepare():Cursor.c第 720 行附近 —Cursor_InternalExecDirect():为什么只改这两处就够了:
prepare和exec_direct是所有 SQL 操作的必经路径(查询/插入/更新/DDL 都走这里)Connection_Ping_inner重连后,下一次 execute 自然会触发 schema 恢复Cursor_SetSchema_And_Parsetype()内部已判断:若connection->schema为None则直接返回 0,零额外开销