-- ============================================================================ -- 1.0.553 · 补 mdp_inbound_grant 缺失的唯一键 uk_inbound_grant(access_key, entity_code) -- -- 背景:1.0.536 里这张表是 CREATE TABLE IF NOT EXISTS。在 1.0.536 正式执行之前, -- 该表已被某个实例的 SqlSugar CodeFirst 抢先建出(CodeFirst 在容器初始化阶段跑, -- 早于 UseAutoVersionUpdate 中间件),于是 1.0.536 的建表语句整条 no-op, -- 脚本里声明的 UNIQUE KEY 从未落地。实测证据:该表无任何 COLUMN COMMENT、 -- 无 DEFAULT,status 是 int 而非脚本声明的 tinyint —— 全是 CodeFirst 产物特征。 -- -- 为什么必须补:mdp_inbound_grant 是第三方推数入站的授权表。 -- (access_key, entity_code) 是它的业务身份:同一凭证对同一实体只应有一条授权。 -- 缺了这个唯一键,重复授权行可以写进去,而入站鉴权按该组合查授权, -- 出现两条就意味着限流配额、IP 白名单、batch 上限到底以哪条为准是不确定的。 -- -- 本脚本只做这一件事。刻意不碰 status 的类型与 DEFAULT、不碰其余四张 inbound 表 —— -- 那些是等价差异,不影响业务语义,混在一起改会让这次热修的回滚面无谓扩大。 -- -- 幂等与安全: -- · 索引不存在 → 创建 -- · 已存在且定义正确 → no-op -- · 同名但定义不对 → SIGNAL 中止,绝不 DROP 重建(可能是别人有意改过) -- · 存在重复数据 → SIGNAL 中止(加唯一键会失败,提前给出可读原因) -- -- AutoVersionUpdate 按分号拆句、无事务,故全部用 PREPARE/EXECUTE 自包含, -- 且注释内不出现会被 parser 误切的分号模式。 -- ============================================================================ -- ── 前置门禁 1:不能有重复数据,否则加唯一键必然失败 ──────────────────────── SET @dup_groups := ( SELECT COUNT(*) FROM ( SELECT 1 FROM `mdp_inbound_grant` GROUP BY `access_key`, `entity_code` HAVING COUNT(*) > 1 ) d ); SET @sql := IF(@dup_groups <> 0, "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '1.0.553-G1: mdp_inbound_grant 存在重复 (access_key, entity_code),无法建唯一键 — 先人工裁决保留哪条'", 'DO 0'); PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s; -- ── 前置门禁 2:同名索引若已存在,定义必须完全正确,否则中止 ──────────────── SET @idx_cols := ( SELECT GROUP_CONCAT(`COLUMN_NAME` ORDER BY `SEQ_IN_INDEX` SEPARATOR ',') FROM information_schema.`STATISTICS` WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_inbound_grant' AND `INDEX_NAME` = 'uk_inbound_grant' ); SET @idx_unique := ( SELECT MIN(`NON_UNIQUE`) FROM information_schema.`STATISTICS` WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_inbound_grant' AND `INDEX_NAME` = 'uk_inbound_grant' ); SET @sql := IF(@idx_cols IS NOT NULL AND (@idx_cols <> 'access_key,entity_code' OR @idx_unique <> 0), "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '1.0.553-G2: uk_inbound_grant 已存在但定义不符预期 — 中止,不自动 DROP 重建'", 'DO 0'); PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s; -- ── 主体:不存在才创建 ────────────────────────────────────────────────────── SET @sql := IF(@idx_cols IS NULL, 'ALTER TABLE `mdp_inbound_grant` ADD UNIQUE KEY `uk_inbound_grant` (`access_key`, `entity_code`)', 'DO 0'); PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s; -- ── 结果断言:执行完必须存在且定义正确 ────────────────────────────────────── SET @after_cols := ( SELECT GROUP_CONCAT(`COLUMN_NAME` ORDER BY `SEQ_IN_INDEX` SEPARATOR ',') FROM information_schema.`STATISTICS` WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_inbound_grant' AND `INDEX_NAME` = 'uk_inbound_grant' AND `NON_UNIQUE` = 0 ); SET @sql := IF(IFNULL(@after_cols, '') <> 'access_key,entity_code', "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '1.0.553-A1: uk_inbound_grant 建后校验失败'", 'DO 0'); PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s; SELECT @after_cols AS uk_inbound_grant_columns;