# ALTER TABLE SQL 產生器與 Dry Run Plan 第一版實作紀錄

## 1. 驗證節點摘要

| 項目 | 內容 |
|---|---|
| 驗證節點名稱 | ALTER TABLE SQL 產生器與 Dry Run Plan 第一版 |
| 驗證日期 | 2026-05-30 |
| 程式 repo | `hs-device-control-template` |
| 實作 commit | `db0b1b8` |
| 驗證分支 | `poc/nmodbus-tcp` |
| 自動測試結果 | `dotnet test` 通過 278 個測試 |
| 狀態 | 已完成第一版驗證 |

本節點依前一份「ALTER TABLE / Schema Initializer 實作前確認」執行，範圍維持在安全邊界內：

- 不新增 MySQL 套件。
- 不連線 MySQL。
- 不查詢 `information_schema`。
- 不執行 DDL。
- 不接 ConsoleHost / ServiceHost / WebApi 啟動流程。

## 2. 已完成範圍

| 項目 | 實際完成內容 |
|---|---|
| Dry Run Plan | 新增 `SchemaMigrationPlan` |
| Operation Model | 新增 `SchemaMigrationOperation` |
| Operation Type | 新增 `SchemaMigrationOperationType` |
| ADD COLUMN SQL | 新增 `GenerateAddColumnSql` |
| ADD INDEX SQL | 新增 `GenerateAddIndexSql` |
| Dry Run 比對 | 新增 `GenerateDryRunPlan` |
| 人工確認項目 | 型別、nullable、primary key、comment、同名 index 定義差異會進 ManualReview |
| 禁止破壞性 SQL | 測試確認不產生 `DROP`、`MODIFY`、`CHANGE` |
| 測試 | 新增 8 個 Core 測試，總測試數由 270 增加為 278 |

## 3. Dry Run 第一版行為

### 3.1 可自動產生 SQL

| 情境 | 輸出 |
|---|---|
| 目標 table 不存在 | `CREATE TABLE IF NOT EXISTS` |
| 目標 column 不存在 | `ALTER TABLE ... ADD COLUMN ...` |
| 目標 index 不存在 | `ALTER TABLE ... ADD INDEX ...` |
| 目標 unique index 不存在 | `ALTER TABLE ... ADD UNIQUE INDEX ...` |

### 3.2 只回報人工確認

| 情境 | 處理方式 |
|---|---|
| 既有欄位型別不同 | 加入 `ManualReviewItems` |
| 既有欄位 nullable / required 不同 | 加入 `ManualReviewItems` |
| primary key 設定不同 | 加入 `ManualReviewItems` |
| comment 不同 | 加入 `ManualReviewItems` |
| 同名 index 欄位或 unique 設定不同 | 加入 `ManualReviewItems` |
| 缺少 primary key 欄位 | 加入 `ManualReviewItems` |

## 4. 實際測試結果

執行指令：

```powershell
dotnet test
```

結果：

| 測試專案 | 通過數 |
|---|---:|
| `HS.DeviceControl.Core.Tests` | 133 |
| `HS.DeviceControl.WorkflowSimulation.Tests` | 11 |
| `HS.DeviceControl.Adapters.Tests` | 108 |
| `HS.DeviceControl.ModbusPoc.Tests` | 26 |
| 合計 | 278 |

測試結果為全部通過。

執行時仍會出現 `.NET 5.0 已不受支援` 的 `NETSDK1138` warning，這是目前指定 .NET 5.0 的預期限制。

## 5. 新增測試涵蓋

| 測試方向 | 驗證結果 |
|---|---|
| `GenerateAddColumnSql` | 可產生 `ALTER TABLE ... ADD COLUMN ...` |
| `GenerateAddIndexSql` | 可產生 `ALTER TABLE ... ADD INDEX ...` |
| Unique index | 可產生 `ADD UNIQUE INDEX` |
| 缺 column / index | Dry Run Plan 會列入 `ColumnsToAdd` / `IndexesToAdd` |
| table 不存在 | Dry Run Plan 會列入 `TablesToCreate` |
| 欄位型別不同 | 進入 `ManualReviewItems` |
| nullable 不同 | 進入 `ManualReviewItems` |
| 同名 index 定義不同 | 進入 `ManualReviewItems` |
| 破壞性 SQL | 測試確認不產生 `DROP`、`MODIFY`、`CHANGE` |

## 6. 尚未完成範圍

| 項目 | 狀態 |
|---|---|
| `information_schema` 查詢 | 尚未導入 |
| MySQL 實際連線 | 尚未導入 |
| DDL 執行器 | 尚未導入 |
| Schema Initializer | 尚未導入 |
| ConsoleHost 啟動自動建表 | 尚未導入 |
| TaskStore 寫入 / 查詢 | 尚未導入 |

## 7. 實際效果

目前已能在不接觸真實 DB 的情況下，先產生「預計要做什麼」的 Dry Run Plan。

這表示後續進入真實 MySQL 前，可以先用程式內的 schema snapshot 測試：

- 會新增哪些 table。
- 會新增哪些 column。
- 會新增哪些 index。
- 哪些差異必須人工處理。
- 是否有任何破壞性 SQL 風險。

本節點讓「自動建表」從單純 `CREATE TABLE` 往前推進到「可描述 schema 差異與可審查 SQL」，但仍未進入真實 DB。

## 8. 建議下一步

建議下一步進入：

> `Schema Inspector / information_schema 實作前確認`

原因：

- Dry Run Plan 已有純程式比對能力。
- 下一步若要知道真實 DB 現況，就需要設計如何查 `information_schema`。
- 這一步會牽涉 MySQL 套件與連線資訊，因此依規則必須先停下確認。

建議先不要直接導入 `MySqlConnector`，而是先整理：

- 需要查哪些 `information_schema` 欄位。
- MySQL 5.6.2 對 `information_schema` 的限制。
- 連線字串與敏感資訊如何提供。
- Inspector 是否只讀不寫。
- 測試要用 mock snapshot、測試資料庫，還是兩者分開。
