fix(dmig): DROP INDEX 被 DROP COLUMN 守卫误解析致静默跳过 + m0038 唯一索引修正
dmig.py 两处(2026-09-17 m0038 部署预演时本地测试抓到): ① `ALTER TABLE t DROP INDEX idx` 会命中 DROP COLUMN 守卫的可选 `(COLUMN\s+)?` 分支,group(3) 捕获到字面词 'INDEX' 而非索引名 → column_exists(t,'INDEX') 恒 False → 整步被静默跳过(索引删不掉、无任何报错)。修: DROP INDEX 守卫 (ALTER 形态 + 独立 `DROP INDEX idx ON t` 形态,历史迁移 m0025/m0031 等 13 条 down 段用的就是独立形态、此前同样无守卫)放在 DROP COLUMN 之前, 幂等判据用 index_exists。 ② DROP COLUMN 正则收紧为强制 COLUMN 关键字后列名组号 3→2,调用点同步 (历史 22 条 DROP COLUMN 全部显式带 COLUMN、bare 形态 0 条,无回归)。 本地守卫测试 18/18 全绿(含 m0038 up/down/重复down 完整生命周期)。 m0038: m0037 把 models 声明的 uk_org_user_name(unique) 误写成普通 CREATE INDEX → 实测建出 KEY 而非 UNIQUE KEY,失去并发去重保护(同名可插重复行、 save_secret 幂等判定失效)。本迁移删误建索引并按 models JSON 权威定义重建 UNIQUE。backup_tables 照旧。不改已应用的 m0037(台账完整性)。
This commit is contained in:
parent
9d668843f1
commit
66996c693d
@ -168,14 +168,38 @@ def render_step(conf, step, direction):
|
||||
if m:
|
||||
if column_exists(conf, m.group(1), m.group(3)):
|
||||
return [], "列已存在: %s.%s" % (m.group(1), m.group(3))
|
||||
# DROP COLUMN 幂等守卫:列已不存在则跳过(生产表由 create_tables.py 按最新
|
||||
# models 建出、天然没有旧列,m0009/m0010 类删列迁移直跑会 1091 中止)
|
||||
m = re.match(r"ALTER\s+TABLE\s+`?(\w+)`?\s+DROP\s+(COLUMN\s+)?`?(\w+)`?", sql, re.I)
|
||||
# DROP INDEX 幂等守卫(2026-09-17 m0038 部署实抓的解析缺陷):
|
||||
# 必须放在 DROP COLUMN 守卫**之前**——后者的可选 `(COLUMN\s+)?` 分支对
|
||||
# `ALTER TABLE t DROP INDEX idx` 同样匹配,且 group(3) 捕获到的是字面词
|
||||
# 'INDEX' 而非索引名 → column_exists(t,'INDEX') 恒 False → 整步被静默跳过
|
||||
# (索引永远删不掉、也不报错)。删索引的正确幂等判据是 index_exists。
|
||||
m = re.match(r"ALTER\s+TABLE\s+`?(\w+)`?\s+DROP\s+INDEX\s+`?(\w+)`?", sql, re.I)
|
||||
if m:
|
||||
if not table_exists(conf, m.group(1)):
|
||||
return [], "表不存在: %s" % m.group(1)
|
||||
if not column_exists(conf, m.group(1), m.group(3)):
|
||||
return [], "列已不存在: %s.%s" % (m.group(1), m.group(3))
|
||||
if not index_exists(conf, m.group(1), m.group(2)):
|
||||
return [], "索引已不存在: %s.%s" % (m.group(1), m.group(2))
|
||||
# 独立形态 DROP INDEX idx ON table(MySQL/MariaDB 同样合法,历史迁移
|
||||
# m0025/m0031 等 13 条 down 段用的就是它)——同款幂等守卫,否则重复
|
||||
# rollback 会 1091 中止。
|
||||
m = re.match(r"DROP\s+INDEX\s+`?(\w+)`?\s+ON\s+`?(\w+)`?", sql, re.I)
|
||||
if m:
|
||||
if not table_exists(conf, m.group(2)):
|
||||
return [], "表不存在: %s" % m.group(2)
|
||||
if not index_exists(conf, m.group(2), m.group(1)):
|
||||
return [], "索引已不存在: %s.%s" % (m.group(2), m.group(1))
|
||||
# DROP COLUMN 幂等守卫:列已不存在则跳过(生产表由 create_tables.py 按最新
|
||||
# models 建出、天然没有旧列,m0009/m0010 类删列迁移直跑会 1091 中止)。
|
||||
# ⚠️ 正则组数是 2(table, col)——原写法带可选 `(COLUMN\s+)?` 组时列名是
|
||||
# group(3),收紧为强制 COLUMN 关键字后列名变成 group(2),索引必须同步改,
|
||||
# 否则 IndexError(2026-09-17 本地测试抓到)。历史迁移 22 条 DROP COLUMN
|
||||
# 全部显式带 COLUMN 关键字、bare 形态 0 条,收紧无回归。
|
||||
m = re.match(r"ALTER\s+TABLE\s+`?(\w+)`?\s+DROP\s+COLUMN\s+`?(\w+)`?", sql, re.I)
|
||||
if m:
|
||||
if not table_exists(conf, m.group(1)):
|
||||
return [], "表不存在: %s" % m.group(1)
|
||||
if not column_exists(conf, m.group(1), m.group(2)):
|
||||
return [], "列已不存在: %s.%s" % (m.group(1), m.group(2))
|
||||
m = re.match(r"CREATE\s+(UNIQUE\s+)?INDEX\s+`?(\w+)`?\s+ON\s+`?(\w+)`?", sql, re.I)
|
||||
if m:
|
||||
if index_exists(conf, m.group(3), m.group(2)):
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
{
|
||||
"id": "m0038",
|
||||
"title": "修正 pipeline_user_secrets 唯一索引(2026-09-17): m0037 把 models 声明的 uk_org_user_name(unique) 误写成普通 CREATE INDEX → 实测建出 KEY 而非 UNIQUE KEY,失去并发去重保护(同名可插重复行、幂等判定失效)。本迁移删除误建的普通索引并按 models JSON 权威定义重建为 UNIQUE。DROP INDEX 用不带 IF EXISTS 的形态(MariaDB 10.6 对 DROP INDEX IF EXISTS 支持不确定,不赌语法),dmig 的 index_exists 守卫已覆盖幂等",
|
||||
"backup_tables": ["pipeline_user_secrets"],
|
||||
"up": [
|
||||
{
|
||||
"op": "sql",
|
||||
"sql": "ALTER TABLE pipeline_user_secrets DROP INDEX pipeline_user_secrets_idx_org_user_name"
|
||||
},
|
||||
{
|
||||
"op": "sql",
|
||||
"sql": "CREATE UNIQUE INDEX uk_org_user_name ON pipeline_user_secrets(org_id, user_id, name)"
|
||||
}
|
||||
],
|
||||
"down": [
|
||||
{
|
||||
"op": "sql",
|
||||
"sql": "ALTER TABLE pipeline_user_secrets DROP INDEX uk_org_user_name"
|
||||
},
|
||||
{
|
||||
"op": "sql",
|
||||
"sql": "CREATE INDEX pipeline_user_secrets_idx_org_user_name ON pipeline_user_secrets(org_id, user_id, name)"
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user