Q 695308f72c feat(ac15): 把「读旧库定义」固化成常备工具 cmd/spdump(并修掉它自己的一个静默错误) 8 小时之前
..
README.md 695308f72c feat(ac15): 把「读旧库定义」固化成常备工具 cmd/spdump(并修掉它自己的一个静默错误) 8 小时之前
main.go 695308f72c feat(ac15): 把「读旧库定义」固化成常备工具 cmd/spdump(并修掉它自己的一个静默错误) 8 小时之前
main_test.go 695308f72c feat(ac15): 把「读旧库定义」固化成常备工具 cmd/spdump(并修掉它自己的一个静默错误) 8 小时之前

README.md

cmd/spdump —— 读旧库定义的常备工具

go run ./cmd/spdump proc sp_user_expense_baddebt          # SHOW CREATE PROCEDURE
go run ./cmd/spdump routines -like "%expense%"            # 有哪些 routine(先看清单)
go run ./cmd/spdump view yuansiwei.t_school_campus        # 跨库视图怎么定义的
go run ./cmd/spdump tables -db finance_bk -like "%activity%"
go run ./cmd/spdump columns t_campus -db yuansiwei_2026    # 列类型/默认值/注释
go run ./cmd/spdump sql -db legacy_oracle "select max(id) from t_courses_activity"

-db 默认 legacy_oracle;flags 与位置参数任意顺序都行。

为什么它必须存在(不是"方便一下")

AC-15 阶段 2 用三次实测证明:「照抄 SP」是不可行的策略 —— 不是因为它难, 是因为旧库里混着错注释和坏 SQL,照抄会把缺陷一起搬过来。

# 事实 如果照抄 / 按名字猜会怎样
1 sp_user_expense_baddebt 的 COMMENT 写着 用户余额充值(从 recharge 复制忘改) 按注释判断会把坏账当成充值
2 sp_user_expense_school_spend 的 INSERT 分支是 INSERT INTO t_user_expense(userid,spend) VALUES(inputUserid, inputMoney, inputSpendMoney) —— 2 列配 3 值,且 inputMoney 在该 SP 里根本不存在 照抄会把这句坏 SQL 搬进 Go;它只在"用户没有账户行"时触发,线上从不走到,所以测也测不出来
3 sp_user_expense_school_transfer_expenditure 没有默认备注(SP1/2/3/4 都有 IF inputRemark='' THEN SET …) 用空备注跑双跑,"备注逐字一致"是空对空,等于没测
4 sp_user_expense.school_cleared_balance 名字叫「余额清零」,实际清的是校区余额,全局只减去同一个 campusBalance 会断言"清零后全局余额 = 0",而它一般不是 0

行为从哪里读:证据强度排序

依据 可靠度 反例
SQL 语句(UPDATE / INSERT / IF 守卫) 最高 无(这是唯一的事实来源)
参数签名 高 无 —— 签名能反推"不可能发生的事":SP11 只有 4 个参数、连 requestId 都没有 ⇒ 它不可能幂等、不可能写流水
自己的 COMMENT 会骗人 baddebt 的注释写着"用户余额充值"
表名 / 函数名 会骗人 t_user_expense 字面像"全局表",实际两个充值 SP 都写双表(这一条当时把 team-lead 也带偏了)

⇒ 证据强度:SQL 语句 > 参数签名 > COMMENT > 表名/函数名。

安全约束(硬性,不是约定)

  • 只连 fixture.allowedDatabases 白名单里的本机库(OpenReadOnlyDB 里守);
  • sql 子命令只接受 SELECT / SHOW / DESC / EXPLAIN / WITH 开头的单条语句(分号后还有内容就拒绝);
  • 连接建立后立刻 SET SESSION TRANSACTION READ ONLY,服务端也会拒绝本会话的写;
  • 口令只经 AC15_* 环境变量或仓库既有 config/dev.json 读取,不打印、不落盘。

一个自己踩过的坑(写在这里免得下一个人再踩)

spdump columns t_campus -db yuansiwei_2026 —— 这种"先对象、后库名"的写法, 如果直接用 Go 的 flag 包解析,-db 会被静默丢弃(flag 遇到第一个非 flag 参数就停止解析), 于是连到默认库、查不到列、打印 (0 行)。

(0 行) 看起来像"这表没有列",是个错误答案,而不是一个错误。 这类失败比报错危险。 所以 main.go 里先做 splitFlagsAndArgs 重排,并有单测锁住(TestSplitFlagsAndArgs)。