|
|
@@ -0,0 +1,126 @@
|
|
|
+-- ============================================================================
|
|
|
+-- 1.0.555 · R2-A2:mdp_entity 两列补 DEFAULT(短期恢复,不动类型)
|
|
|
+--
|
|
|
+-- 为什么需要本脚本(1.0.554 的效果被撤销,已实证):
|
|
|
+-- 1.0.554 把 inbound_enabled / stale_guard_enabled 收口为 TINYINT + DEFAULT,
|
|
|
+-- migration 与 verify 均 Success。但下一次启动时 SqlSugar CodeFirst
|
|
|
+-- (EnableInitTable=true)按实体声明 `public int` 把它们改回 INT,
|
|
|
+-- 其 ALTER 形态为 `alter table t change column c c int NOT NULL`——
|
|
|
+-- 不带 DEFAULT 子句,于是连带抹掉 DEFAULT。
|
|
|
+-- 对照组:inbound_max_rows 类型本就等于实体声明的 INT,CodeFirst 无差异
|
|
|
+-- 可纠正、不生成 ALTER,其 DEFAULT 500 完整穿越了一次 CodeFirst 遍历。
|
|
|
+--
|
|
|
+-- 结论:只要列类型与实体声明一致,CodeFirst 就不会重写该列,DEFAULT 得以存活。
|
|
|
+-- 故本批策略 = 类型保持 INT(与实体一致),只补 DEFAULT。
|
|
|
+-- 类型漂移(INT vs 契约 TINYINT)留 R2-B,待 CodeFirst schema authority 定案。
|
|
|
+--
|
|
|
+-- 1.0.554 保持历史不变:不修改、不改 hash、不改 migration log、不重放。
|
|
|
+--
|
|
|
+-- 算法:本地 3307 实测 ALTER COLUMN ... SET DEFAULT 接受 INSTANT / INPLACE,LOCK=NONE
|
|
|
+-- / COPY 三者。取 INSTANT(纯元数据变更,不重建表,无写阻塞),实测 58ms。
|
|
|
+--
|
|
|
+-- 范围:只动 mdp_entity 的 inbound_enabled / stale_guard_enabled 两列的 DEFAULT。
|
|
|
+-- inbound_max_rows 只做前置断言,绝不 ALTER。
|
|
|
+-- 不碰 MdpEntity.cs / CodeFirst / EnableInitTable / R2-B / P0 / 1.0.554。
|
|
|
+-- ============================================================================
|
|
|
+
|
|
|
+-- ── G1 表存在 ───────────────────────────────────────────────────────────────
|
|
|
+SET @t := (SELECT COUNT(*) FROM information_schema.`TABLES`
|
|
|
+ WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_entity');
|
|
|
+SELECT IF(@t <> 1, 'R2A2-G1 FAIL: mdp_entity 不存在', 'R2A2-G1 ok') AS gate_g1;
|
|
|
+SET @sql := IF(@t <> 1,
|
|
|
+ "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'R2A2-G1: mdp_entity 不存在,中止'", 'DO 0');
|
|
|
+PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
|
|
+
|
|
|
+-- ── G2 inbound_enabled 无 NULL ─────────────────────────────────────────────
|
|
|
+SET @g2 := (SELECT COUNT(*) FROM `mdp_entity` WHERE `inbound_enabled` IS NULL);
|
|
|
+SELECT @g2 AS g2_null_rows;
|
|
|
+SELECT IF(@g2 <> 0, 'R2A2-G2 FAIL: inbound_enabled 存在 NULL', 'R2A2-G2 ok') AS gate_g2;
|
|
|
+SET @sql := IF(@g2 <> 0,
|
|
|
+ "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'R2A2-G2: inbound_enabled 存在 NULL,中止'", 'DO 0');
|
|
|
+PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
|
|
+
|
|
|
+-- ── G3 stale_guard_enabled 无 NULL ─────────────────────────────────────────
|
|
|
+SET @g3 := (SELECT COUNT(*) FROM `mdp_entity` WHERE `stale_guard_enabled` IS NULL);
|
|
|
+SELECT @g3 AS g3_null_rows;
|
|
|
+SELECT IF(@g3 <> 0, 'R2A2-G3 FAIL: stale_guard_enabled 存在 NULL', 'R2A2-G3 ok') AS gate_g3;
|
|
|
+SET @sql := IF(@g3 <> 0,
|
|
|
+ "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'R2A2-G3: stale_guard_enabled 存在 NULL,中止'", 'DO 0');
|
|
|
+PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
|
|
+
|
|
|
+-- ── G4 行数基线(只记录,不硬编码)────────────────────────────────────────
|
|
|
+SET @rows_before := (SELECT COUNT(*) FROM `mdp_entity`);
|
|
|
+SELECT @rows_before AS rows_before;
|
|
|
+
|
|
|
+-- ── G5 inbound_max_rows 必须已是 INT NOT NULL DEFAULT 500 ──────────────────
|
|
|
+-- 它由 1.0.554 修好并已穿越一次 CodeFirst 遍历;若 500 丢失说明前提变了,
|
|
|
+-- 属 SCOPE CHANGED,本脚本不得顺手补。
|
|
|
+SET @g5 := (SELECT COUNT(*) FROM information_schema.`COLUMNS`
|
|
|
+ WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_entity'
|
|
|
+ AND `COLUMN_NAME` = 'inbound_max_rows'
|
|
|
+ AND `COLUMN_TYPE` = 'int' AND `IS_NULLABLE` = 'NO'
|
|
|
+ AND `COLUMN_DEFAULT` <=> '500');
|
|
|
+SELECT @g5 AS g5_inbound_max_rows_ok;
|
|
|
+SELECT IF(@g5 <> 1,
|
|
|
+ 'R2A2-G5 FAIL: inbound_max_rows 不是 INT NOT NULL DEFAULT 500 — SCOPE CHANGED',
|
|
|
+ 'R2A2-G5 ok') AS gate_g5;
|
|
|
+SET @sql := IF(@g5 <> 1,
|
|
|
+ "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'R2A2-G5: inbound_max_rows 不符前提(应为 INT NOT NULL DEFAULT 500),SCOPE CHANGED,中止'",
|
|
|
+ 'DO 0');
|
|
|
+PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
|
|
+
|
|
|
+-- ── G6 类型守卫:两列必须已是 INT NOT NULL;本脚本不改类型 ──────────────────
|
|
|
+SET @g6 := (SELECT COUNT(*) FROM information_schema.`COLUMNS`
|
|
|
+ WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_entity'
|
|
|
+ AND `COLUMN_NAME` IN ('inbound_enabled', 'stale_guard_enabled')
|
|
|
+ AND `COLUMN_TYPE` = 'int' AND `IS_NULLABLE` = 'NO');
|
|
|
+SELECT @g6 AS g6_int_notnull_cols;
|
|
|
+SELECT IF(@g6 <> 2,
|
|
|
+ 'R2A2-G6 FAIL: 两列类型不是 INT NOT NULL — 本脚本不自动改类型',
|
|
|
+ 'R2A2-G6 ok') AS gate_g6;
|
|
|
+SET @sql := IF(@g6 <> 2,
|
|
|
+ "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'R2A2-G6: inbound_enabled / stale_guard_enabled 类型不是 INT NOT NULL,本脚本不自动改类型,中止'",
|
|
|
+ 'DO 0');
|
|
|
+PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
|
|
+
|
|
|
+-- ── Step 1 · 逐列目标态比对(NULL-safe <=>),仅对仍漂移的列生成子句 ────────
|
|
|
+SET @need_ie := (SELECT COUNT(*) FROM information_schema.`COLUMNS`
|
|
|
+ WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_entity'
|
|
|
+ AND `COLUMN_NAME` = 'inbound_enabled'
|
|
|
+ AND NOT (`COLUMN_DEFAULT` <=> '0'));
|
|
|
+SET @need_sg := (SELECT COUNT(*) FROM information_schema.`COLUMNS`
|
|
|
+ WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_entity'
|
|
|
+ AND `COLUMN_NAME` = 'stale_guard_enabled'
|
|
|
+ AND NOT (`COLUMN_DEFAULT` <=> '1'));
|
|
|
+SELECT @need_ie AS need_inbound_enabled, @need_sg AS need_stale_guard_enabled;
|
|
|
+
|
|
|
+-- CONCAT_WS 会跳过 NULL,于是只有需要改的列才进入 ALTER 子句
|
|
|
+SET @c1 := IF(@need_ie > 0, 'ALTER COLUMN `inbound_enabled` SET DEFAULT 0', NULL);
|
|
|
+SET @c2 := IF(@need_sg > 0, 'ALTER COLUMN `stale_guard_enabled` SET DEFAULT 1', NULL);
|
|
|
+SET @clauses := CONCAT_WS(', ', @c1, @c2);
|
|
|
+
|
|
|
+-- ── Step 2 · 仅在有漂移列时执行;ALGORITHM=INSTANT(纯元数据,无写阻塞)────
|
|
|
+SET @sql := IF(@clauses IS NULL OR @clauses = '',
|
|
|
+ 'DO 0',
|
|
|
+ CONCAT('ALTER TABLE `mdp_entity` ', @clauses, ', ALGORITHM=INSTANT'));
|
|
|
+SELECT @sql AS planned_statement;
|
|
|
+PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
|
|
+
|
|
|
+-- ── Step 3 · 事后自断言:两列 DEFAULT 必须到位 ─────────────────────────────
|
|
|
+SET @after := (SELECT COUNT(*) FROM information_schema.`COLUMNS`
|
|
|
+ WHERE `TABLE_SCHEMA` = DATABASE() AND `TABLE_NAME` = 'mdp_entity'
|
|
|
+ AND ((`COLUMN_NAME` = 'inbound_enabled' AND `COLUMN_DEFAULT` <=> '0')
|
|
|
+ OR (`COLUMN_NAME` = 'stale_guard_enabled' AND `COLUMN_DEFAULT` <=> '1')));
|
|
|
+SELECT @after AS defaults_in_place;
|
|
|
+SELECT IF(@after <> 2, 'R2A2-POST1 FAIL: 两列 DEFAULT 未全部到位', 'R2A2-POST1 ok') AS gate_post1;
|
|
|
+SET @sql := IF(@after <> 2,
|
|
|
+ "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'R2A2-POST: 两列 DEFAULT 未全部到位,中止'", 'DO 0');
|
|
|
+PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|
|
|
+
|
|
|
+-- ── Step 4 · 行数完整性 ────────────────────────────────────────────────────
|
|
|
+SET @rows_after := (SELECT COUNT(*) FROM `mdp_entity`);
|
|
|
+SELECT @rows_before AS rows_before, @rows_after AS rows_after;
|
|
|
+SELECT IF(@rows_after <> @rows_before, 'R2A2-POST2 FAIL: 行数变化', 'R2A2-POST2 ok') AS gate_post2;
|
|
|
+SET @sql := IF(@rows_after <> @rows_before,
|
|
|
+ "SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'R2A2-POST: mdp_entity 行数在 ALTER 前后不一致,中止'", 'DO 0');
|
|
|
+PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
|