taosdata / taosdata/TDengine

taospy` 原生驱动的 `cursor.execute(sql, params)` 方法在处理参数绑定时存在Bug

Open
#34,154 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
C
Stars
25.1k
Forks
5k
Avg merge
4d 59m
Merged PRs (30d)
7

Description

Bug Description
A clear and concise description of what the bug is.
│ 1 # TDengine Saga 事务修复与 taospy 驱动问题排查报告 │
│ 2 │
│ 3 ## 1. 核心问题描述 │
│ 4 │
│ 5 在实现跨数据库(PostgreSQL + TDengine)的 Saga 分布式事务时,遇到了核心阻塞性问题:TDengine 的 Saga 补偿机制失效。 │
│ 6 │
│ 7 - 原始设计:利用 TDengine 的 TAGS 存储事务 ID (txn_id) 和有效性标记 (is_valid),通过修改 Tag 来实现逻辑删除(补偿)。 │
│ 8 - 技术限制:TDengine 不支持直接对超级表(STABLE)执行 UPDATE ... SET TAG ... 操作,导致无法在事务失败时批量标记数据失效。 │
│ 9 │
│ 10 ## 2. 解决方案:Schema 迁移 │
│ 11 │
│ 12 为了规避 Tag 更新限制,我们实施了 Schema 迁移方案: │
│ 13 │
│ 14 - 变更内容:将 txn_idis_validTAGS 迁移为 数据列 (Columns)。 │
│ 15 - 优势: │
│ 16 - 数据列支持在写入时直接指定。 │
│ 17 - 虽然 TDengine 对普通列的更新支持有限,但我们可以采用 "Copy-on-Write" (查询 -> 标记 -> 重写) 策略,利用 TDengine 的自动去重机制(基于时间戳 + │
│ Tags)覆盖旧数据,从而实现软删除。 │
│ 18 │
│ 19 ## 3. taospy 驱动 Bug 排查与修复 │
│ 20 │
│ 21 在实施新方案并运行测试时,遇到了极具迷惑性的错误,排查过程如下: │
│ 22 │
│ 23 ### 3.1 异常现象 │
│ 24 测试脚本报错:k线插入错误: Invalid isoformat string: 'T'。 │
│ 25 │
│ 26 ### 3.2 排查过程 │
│ 27 1. 初步怀疑:时间戳格式问题。 │
│ 28 - 尝试:将 pandas.Timestamp 转换为纯 Python datetime 对象,甚至格式化为字符串。 │
│ 29 - 结果:无效,错误依旧。 │
│ 30 2. 二次怀疑:WebSocket 驱动 (taosws) 问题。 │
│ 31 - 尝试:强制切换回原生驱动 (taos/taospy)。 │
│ 32 - 结果:无效,且错误信息变为 Invalid isoformat string: 'A'(当测试符号改为 AAAA001 时)。 │
│ 33 3. 根因定位: │
│ 34 - 观察到错误字符 'T''A' 分别对应测试用的 Symbol (TEST001AAAA001) 的首字母。 │
│ 35 - 结论taospy 原生驱动的 cursor.execute(sql, params) 方法在处理参数绑定时存在严重 Bug。它错误地尝试解析第一个字符串参数(本例中为 symbol
│ 标签),误判其为日期格式并尝试进行 ISO 格式转换,导致报错。 │
│ 36 │
│ 37 ### 3.3 最终修复 │
│ 38 为了绕过驱动层的参数解析 Bug,我们在 TDengineDataAccess 中采取了直接构建 SQL 的策略: │
│ 39 │
│ 40 - 弃用cursor.execute(sql, params)
│ 41 - 采用:使用 f-string 构建完整的 SQL 字符串,手动处理类型转换和引号转义。 │
│ 42 │
│ 43 python │ │ 44 # 修复前 (触发驱动 Bug) │ │ 45 cursor.execute("INSERT INTO ... VALUES (?, ...)", params) │ │ 46 │ │ 47 # 修复后 (绕过驱动解析) │ │ 48 sql = f"INSERT INTO ... VALUES ('{ts_str}', {price}, ...)" │ │ 49 cursor.execute(sql) │ │ 50
│ 51 │
│ 52 ## 4. 架构一致性修复 │
│ 53 │
│ 54 在排查过程中,还发现项目存在架构不一致问题: │
│ 55 - 问题:存在两套数据访问层代码 (src/data_access/src/storage/access/)。 │
│ 56 - 修复:确认 DataManager使用的是 src/data_access/,因此将所有修复(Schema 变更、SQL 构建逻辑)统一合并到了 src/data_access/tdengine_access.py
│ 中,解决了代码修改不生效的问题。 │
│ 57 │
│ 58 ## 5. 验证结果 │
│ 59 │
│ 60 运行 tests/test_saga_transaction.py 验证通过: │
│ 61 1. 成功场景:数据正确写入 TDengine,is_valid=true。 │
│ 62 2. 失败补偿:PG 元数据更新失败触发 Saga 回滚,TDengine 对应数据被成功标记为 is_valid=false

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Type in '....'
  3. See error

Expected Behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Environment (please complete the following information):
TDengine Community Edition
taos version: 3.3.6.13 compatible_version: 3.0.0.0
git: 1a3a182ba16ee188c0677fb6cd637b34c52f6bd7
build: Linux-x64 2025-06-28 22:48:07 +0800

Additional Context
Add any other context about the problem here.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The report identifies taospy’s native cursor.execute(sql, params) path and shows a failing parameterized INSERT, but it does not name a TDengine source file or provide complete reproduction steps. Start by reproducing the Invalid isoformat error with the shown symbol values, then compare the behavior with tests/test_saga_transaction.py and the cited src/data_access/tdengine_access.py workaround. Done means string symbols no longer trigger date parsing and a regression test passes.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, sql
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.