docs(debt): 补记之十二/十三 —— pi 陷阱①复现成立且**修法已实测跑通**;★★ 陷阱②它的**理由方向反了**(会导出错误动作)
① ★★★★ 陷阱①(逐条 Exec ⇒ 各自 auto-commit ⇒ DROP 后崩)—— **我独立复现,完全成立**:
播下 aps 行数=1 → 建 _new → 拷贝 → DROP ⇒ `aps` 存在=**0**、`aps_new` 行数=1
下次启动: `CREATE TABLE IF NOT EXISTS aps(新PK)` 建出**空表** ⇒ 实测行数=**0**(线上即 37 行)
守卫只看 PK ⇒ PK **已正确** ⇒ **跳过重建** ⇒ **永不自愈**; 而判据 (a)(b) 此时**全绿**
⇒ 绿着丢数据
② ★★ 修法**实测跑通**(非纸面): 同一 `BEGIN…COMMIT` 内 建 _new→拷贝→DROP→RENAME→**重建索引**
⇒ 行数=1(保住)✓ 索引=1(补回)✓ `_new` 残留=0 ✓ PK=(a,b,w) ✓
⇒ 索引那条**必须写在 RENAME 之后且在事务内**(写在 RENAME 之前会被 init DDL 那句空转掩盖)
⇒ 采纳 pi 的"④ 从『保证顺序』改成『**事务内显式重建索引**』"—— 顺序依赖被事务消掉
⇒ ⚠️ 但**仅靠事务不够**: 防不了"上一版已崩"留下的孤儿 `_new` ⇒ 判据 (c) 与孤儿可恢复是**必需**第二道
③ ★★★ 陷阱②(守卫不能用 LIKE)—— 陷阱为真,但**理由方向反了**:
pi 说: "'…PRIMARY KEY (…' **带空格**,**实际无空格**"
★ 我实测: `sqlite_master.sql` **逐字保留**建表语句、不规范化空白
建 `PRIMARY KEY (a, b)` ⇒ 库里带空格 ⇒ **带空格的 LIKE 命中**
建 `PRIMARY KEY(a, b)` ⇒ 库里无空格 ⇒ 带空格的 LIKE **不命中**
线上实测: `agent_platform_sessions` 的 `PRIMARY KEY (agent_name, platform_id)` **带空格**、
`LIKE '%PRIMARY KEY (agent_name, platform_id)%'` **命中=1** ✓
`init_sqlite.sql:421`(及 :328/:380/:389)用的**就是**带空格写法
⇒ ★★ 真正机制: **LIKE 命中与否取决于当初 DDL 的书写风格**,而书写风格不是不变量
⇒ 结论与 pi **一致**(用 `pragma_table_info` 的 pk 列,别用 LIKE)但**理由不同**
⇒ ⚠️★ 照 pi 的理由去改(例如为"匹配无空格"把 DDL 改成紧凑写法)**恰好制造它描述的故障**:
改完 DDL 后老库 `sqlite_master.sql` 仍是旧样式(IF NOT EXISTS 不重写)⇒ LIKE 反而不命中
⇒ ★ 本轮最值得记的: **正确结论 + 错误理由 ⇒ 导出错误动作**(我差点照错误理由去改)
校验: go test ./internal/repo/ -run Debt -count=1 ⇒ ok; /tmp/v1 已清; 未改产品代码
This commit is contained in:
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user