From deb82f133cb323e0ea41194b316b72bc25989985 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 20:57:50 +0800 Subject: [PATCH 01/26] docs: record MSSQL import wizard design and snapshots --- docs/design/mssql-import/design.md | 182 ++++++++++++++++++ docs/design/mssql-import/index.html | 149 ++++++++++++++ .../mssql-import/snapshot/error-log-dark.jpg | Bin 0 -> 114885 bytes .../mssql-import/snapshot/progress-light.jpg | Bin 0 -> 106070 bytes 4 files changed, 331 insertions(+) create mode 100644 docs/design/mssql-import/design.md create mode 100644 docs/design/mssql-import/index.html create mode 100644 docs/design/mssql-import/snapshot/error-log-dark.jpg create mode 100644 docs/design/mssql-import/snapshot/progress-light.jpg diff --git a/docs/design/mssql-import/design.md b/docs/design/mssql-import/design.md new file mode 100644 index 0000000..1c84890 --- /dev/null +++ b/docs/design/mssql-import/design.md @@ -0,0 +1,182 @@ +# MSSQL SQL 檔匯入精靈設計 + +日期:2026-10-13 +基底:master,d45c903(已合併 MSSQL 匯出修正) +狀態:使用者已同意四步畫面原型;本文件供正式規格審閱,尚未進入實作計畫或產品實作。 + +## 1. 需求與本次範圍 + +把 MSSQL 的「執行 SQL 檔/匯入」升級成專用精靈,支援 mySQLPunk 匯出的數 GiB SQL 檔及一般 T-SQL/GO。沿用匯出精靈的 Punky、自動循環動畫、一次聲音與靜音、進度、預估剩餘時間及預計完成時間。 + +使用者可勾選「遇到 SQL 錯誤時,略過失敗批次並繼續」,預設不勾。所有錯誤都寫入本機 error log;畫面提供唯讀 textarea,數量太多時顯示最近一段並清楚標示完整 log 路徑。 + +這次只改 MSSQL 的檔案執行入口,保留 MySQL/MariaDB/SQLite 及一般查詢編輯器的既有行為。支援順序執行,不做平行匯入、斷點續傳、自動重試、SQLCMD 指令、原生 .bak 還原或自動清空資料庫。 + +### 現有問題與方案選擇 + +舊入口會把檔案整份讀成 byte[]/string,再依分號拆解並使用共用 provider;不支援 GO、獨立取消或可信進度,傳入的 databaseName 也沒有在執行前明確切換。新流程使用獨立擁有的連線與串流 GO reader,不把大檔交給舊 splitter。 + +| 方案 | 取捨 | +| --- | --- | +| 程式內串流 GO reader+專用 SqlClient session(採用) | 能取得每個批次的實際回應、錯誤、取消與進度;須完整驗證 lexer 及 bounded memory | +| 呼叫外部 sqlcmd | 可作獨立驗證工具,但需處理版本、外部程序及每批回應;不作精靈主要執行器 | +| 擴大舊整檔讀取流程 | 記憶體隨檔案增加,也無法保持正確 GO/LOB session 行為,不採用 | + +## 2. 已核准畫面與保存位置 + +互動原型:[index.html](index.html)。原型的 SQL 執行、error log 與數值均為模擬,不連接 DB,也不寫入實際匯入紀錄。 + +截圖存入本設計的 `snapshot/`,保留原始瀏覽器截圖,沒有重新縮圖: + +| 畫面 | 圖片 | +| --- | --- | +| 淺色,匯入進度、ETA 與 Punky | [progress-light.jpg](snapshot/progress-light.jpg) | +| 深色,帶錯誤完成與大量 error log | [error-log-dark.jpg](snapshot/error-log-dark.jpg) | + +四步流程如下: + +1. **檔案與目標**:選 SQL 檔,顯示大小、編碼、來源摘要及實際解析的 server/instance/database。使用既有連線設定;本次本機試跑使用 Windows 整合登入。 +2. **匯入檢查**:完整串流預掃描,檢查 GO/編碼/批次上限、檔案完整標記、目標狀態、基本權限與 log 可寫性。顯示掃描進度,失敗時指出批次/行號並停用下一步。 +3. **確認執行**:再次顯示檔案、實際目標、錯誤政策、log 路徑及部分寫入可能保留的說明。略過錯誤預設關;使用者確認目標後才可開始。 +4. **執行與結果**:依序送出批次,顯示已處理檔案範圍、成功/失敗批次、目前行號、已用時間、ETA 與最近錯誤。結束後保留結果與 log 開啟/資料夾/複製路徑功能。 + +Punky 預設自動循環播放,不設播放或暫停按鈕;聲音僅首輪一次,可靜音。執行、停止中、完成、帶錯誤及失敗使用既有素材與狀態文案。過程中取消按鈕保持可到達;視窗縮放、高 DPI、深淺色與鍵盤操作均須驗證。 + +## 3. 檔案預掃描與 GO 規則 + +檔案以唯讀 handle 開啟,採 `FileShare.Read`,在預掃描、確認與執行期間持續持有;離開精靈或更換檔案才釋放。無法取得穩定讀取 handle 時不開始。預掃描只讀檔與 DB metadata,不執行檔內 SQL。 + +採兩次順序讀取:先完整掃描取得總 bytes/批次數/最大批次/SHA-256/格式資訊,再 rewind 同一個 handle 執行。兩次都用固定 buffer,不保存所有 batch 或全部行號索引。更換檔案、目標或關鍵設定會使預檢失效;開始前再次讀取目標狀態。 + +- v1 支援嚴格 UTF-8(有/無 BOM)及有 BOM 的 UTF-16 LE/BE;拒絕無法判定或有無效序列的編碼,不能以替代字元默默執行。來源檔案不改寫。 +- GO 不分大小寫,須位於字串、quoted identifier、bracket identifier 與註解之外的獨立一行。支援前後空白及 `GO -- 註解`;GO 不送給 SQL Server。v1 不支援 GO 重複次數與同一分隔行的 block comment,預掃描發現這類 GO 語法時明確拒絕。 +- lexer 跨 buffer 維持狀態,處理單引號/N 字串與 `''`、雙引號與 `""`、方括號與 `]]`、單行註解、巢狀 block comment、CRLF/LF 及多位元字元。字串/註解中的 GO 保留原文。行本身也不得以無上限 ReadLine 累積。 +- EOF 的最後一個非空批次照常執行;未閉合的字串、identifier 或 block comment 在預掃描擋下。空批次不送出,不用分號拆解任意 T-SQL。 +- `:r`、`:setvar`、`:connect`、`!!` 等 SQLCMD 指令在有效指令位置出現時拒絕;不展開 `$(name)`,字串中的相同文字維持原值。 + +**單一 GO 批次上限為解碼後 32 MiB,即 16,777,216 個 UTF-16 code unit。** 超過時於預掃描、任何 DB 寫入前停止,列出批次及行號。不能插入 GO 或用分號硬切來避開限制。這是執行批次的記憶體界限,不是欄位大小限制:數十 MiB 甚至更大的文字/binary/Geometry 仍可透過既有分段腳本跨批次匯入。 + +既有 exporter 的資料批次最多約 4 MiB UTF-8,LOB chunk 更小;schema/view 定義沒有同樣的通用上限,仍須實測預掃描。32 MiB 也不是整個程序的總記憶體承諾,StringBuilder、最終 string 及 SqlClient 可能同時持有多份;驗收要量測峰值及長時間記憶體是否隨檔案成長。 + +辨識目前 mySQLPunk 完整匯出檔時讀取 footer 的 job/tables/rows 及來源讀取模式;缺少或格式不完整的 native 完成標記不視為可完整還原的匯出檔。一般 T-SQL 不要求該 footer,但顯示「無匯出筆數摘要」。識別規則以既有 exporter 的結構及受控 marker 為準;註解與 footer 都不是簽章或安全認證。執行時再計算串流 digest 與預掃描比對,差異會令結果失敗,不能藉此回復已執行的 SQL。 + +## 4. 專用連線、目標與交易 + +每個作業經既有 `ConnectionOpenService`/owned session 開啟專用連線,以選定的 Initial Catalog 明確指定目標。複製必要的連線設定,不借用資料庫樹或查詢頁面的共用 provider;SSH owner 也隨本次 session 釋放。所有 GO 批次都使用這個 session,不自動重連或換線。 + +開始時記錄實際 server/instance、版本、DB_NAME、database_id、可寫狀態及目前登入可見的 metadata。確認頁與結果頁顯示解析後的實際目標;讀取失敗、目標消失/唯讀、身份不符或無法確認必要條件時不開始。沒有 sysadmin/ALTER DATABASE 並非一律拒絕的理由;依腳本範圍檢查基本建立/寫入能力,實際 SQL 權限錯誤仍需完整記錄。 + +辨識為包含建立結構的 mySQLPunk 匯出檔時,目標須無使用者資料表/檢視/程序等物件,且需有足夠 metadata 可見性來確認;資料庫既有 schema 本身不代表非空。資料型匯出與一般 T-SQL 不一律要求空庫。權限或語法預檢不是任意 SQL 能成功的證明,也不能靠試跑 SQL 檢查權限。 + +精靈不會自動建立、清空、覆寫資料庫,不切 recovery model、不開關 SNAPSHOT、不發 GRANT 或 KILL,也不會放寬外鍵/檢查約束。使用者選擇執行的 SQL 本身仍可變更資料;一般腳本依 SQL Server 原有權限執行,本功能不是 SQL sandbox。 + +v1 不接受獨立 T-SQL `USE` 切換至其他資料庫;lexer 能辨識這類直接語法並在預掃描擋下。三段名稱、動態 SQL 或 stored procedure 仍可能存取其他 DB,不能宣稱 target pinning 會攔住所有跨庫存取;執行前文案須要求使用者確認腳本來源與目標。每批完成再確認目前 database_id,發現改變就停止。 + +保留批次原文、順序及 session 的 SET、IDENTITY_INSERT、temp table、LOB staging 狀態。不中途插入全檔外層 transaction,也不改寫腳本自己的 transaction;允許一般腳本的交易跨 GO,但這種情況遇錯不能套用自動略過。 + +成功回應只代表這個 batch 已完成執行,不代表其中的交易已提交;失敗/取消批次也可能已部分寫入。先前已提交的變更不會因取消整份還原。自然 EOF 尚有未結交易時不能顯示成功;停止後嘗試回復本次專用 session 的未提交交易並釋放連線,回復失敗或結果不明須記錄。 + +## 5. 順序執行、大欄位與錯誤政策 + +worker 一次最多執行一個 SqlCommand,下一批在前一批結果已處理後才送出。CommandTimeout 預設 0(允許長指令),取消機制獨立可用;若未來加入有限 timeout,timeout 一律停止,不自動重試。產生結果集的一般 T-SQL 也要逐 result/逐 row 讀完並丟棄,不建 DataTable 或將整個結果載入畫面。 + +mySQLPunk LOB/Geometry 使用同一 job 的 `#mp__*` temp tables,維持原本順序/長度/Consumed/Failed 檢查,Geometry 依原腳本 Deserialize。不能清除失敗旗標、跳過 chunk 或重播已消耗 row 來假裝完成。 + +| 情況 | 行為 | +| --- | --- | +| 預設未勾略過,收到 SQL 錯誤 | 記完整 log,停止排程,結果為失敗 | +| 已勾略過,一般 SQL 錯誤符合下述條件 | 記完整 log,略過失敗的 GO batch,再送下一批;最後為「執行完成,但有錯誤」 | +| timeout、取消、斷線、嚴重錯誤、未知執行結果 | 停止;不假裝是可略過的普通錯誤 | +| parser/編碼/檔案 IO/log IO 錯誤 | 停止;不得在沒有可保存錯誤紀錄的狀態繼續 | +| 未結/不可提交/無法查明的交易,或 LOB 協定失敗 | 即使勾略過仍停止,保留可追查狀態 | + +一般 SQL 錯誤只有在以下條件全部成立時才可略過: + +1. 使用者已勾選;原連線仍開啟,未收到取消;錯誤屬一般 SQL 錯誤(class 11–16),不是 timeout/attention/傳輸錯誤或 native 協定錯誤。 +2. 本批執行前與錯誤後均能確認 `@@TRANCOUNT=0`、`XACT_STATE()=0`,且目前仍為選定 database_id;狀態查詢使用獨立 5 秒 timeout,失敗就停止。 +3. 該 batch 不涉及 native LOB 初始化/組裝/提交,且已辨識的 job 狀態沒有 Failed、未消耗 row 或不符預期的狀態;無法確認狀態就停止。 +4. 本批所有 SQL error detail 均已成功寫入並 flush 至 log。 + +以 provider 錯誤碼、class、交易狀態及受控協定識別判定,不以英文/中文 error message 字串決定恢復。native 批次識別與 temp identifier 必須經 lexer 及 GUID 格式驗證;不能把任意 footer 內容接成 SQL。初始化尚未發生與預期 state table 卻遺失須分開。 + +特別注意:LOB CATCH 會先 rollback 短交易,再把 temp state 的 Failed 設為 1。因此交易已回到 0 仍不表示可繼續,包含最後 INSERT 的轉型/約束失敗也要停止。無法安全辨識的 native 狀態採停止,不能默默降為一般略過。 + +「略過」是失敗 batch,不是單一 row;同批已生效的 SQL 不會自動撤回。成功數、失敗/略過數及當前結果不確定的批次分開,不能由 ExecuteNonQuery 的 affected rows 推算實際匯入筆數,因為 LOB staging 更新也會計入。 + +## 6. Error log 與 UI 記憶體界限 + +每次作業建立獨立 UTF-8 log,預設 `%LOCALAPPDATA%\mySQLPunk\ImportLogs\import--.log`。開始 DB 寫入前必須已成功建立並寫入作業表頭;檔名唯一且不覆寫既有 log。檔案路徑在確認、執行與結果頁可見。 + +表頭包含 job、來源路徑/大小/digest/編碼、實際 server/database、錯誤政策與開始時間。每個 SQL 錯誤保存時間、batch Int64 序號、來源行範圍與原始 byte 範圍、provider error number/state/class/相對與換算行號/message、採取的動作及狀態檢查結果。多個 SqlError 都要記錄,不只第一個。完整 log 指所有錯誤都有紀錄,不額外附整段 SQL、LOB payload、連線字串或密碼;SQL Server 原始錯誤訊息本身可能含資料值,紀錄維持本機使用者目錄。 + +error log 串流追加,每次要略過前 flush;錯誤不能累積到最後才存。job 結尾寫入結果、成功/失敗/未確認批次統計、最後確認位置、取消及 cleanup 結果。log 建立/追加/flush 失敗就停止,畫面保留 bounded 最新錯誤及存檔失敗原因,不宣稱完整 log 已保存。 + +textarea 唯讀,以 ring buffer 保留最近 100 筆或 64 KiB UTF-16 文字(先到者為準),單筆過長只截 UI。總錯誤數另以 Int64 累計;不要在記憶體保存所有錯誤/失敗批次或每批 log string。截段文案顯示「僅顯示最近 … 筆;共 … 筆,完整紀錄:」。開啟完整 log/資料夾/複製路徑直接作用於實際已建立的檔案;成功、帶錯誤、失敗與取消都保留紀錄。 + +## 7. 進度、ETA 與結果核對 + +預掃描與執行分開計算進度。執行進度以原始 bytes 為基礎,只在 command 已取得結果並完成處理後推進;不能用 read-ahead 的 FileStream.Position 當已匯入進度。成功覆蓋 bytes 與失敗/略過覆蓋 bytes 分開,勾略過時主標籤為「已處理檔案範圍」,不可把 100% 說成全部成功。 + +UI 約每 200 ms 合併更新,worker 不對每個 row/chunk 送 UI invoke。目前 batch 序號、來源行範圍與已確認邊界使用 Int64。只有能由 native 格式可靠辨識的表名/階段才顯示,否則顯示目前批次;不猜測任意 T-SQL 的物件清單。 + +ETA 採最近約 10 秒已確認處理 bytes 的速率,至少 3 次樣本、2 秒觀察後才顯示「約 …/預計 …」。5 秒無新確認、長指令、索引/約束階段或波動太大時改顯示「計算中/目前指令執行中」,不倒數至負數、不把讀完檔案等同工作結束。建立索引、外鍵與結果核對完成前仍為執行中;預掃描、執行及結果核對各有狀態。 + +所有跑到 EOF 的作業(包含已略過錯誤者)都必須檢查 session/交易與檔案 digest。所有已辨識的 native 模式(含 DataOnly)若曾初始化 LOB,結尾須確認預期 state table 存在且只有一筆、Failed=0、Consumed=1、Sequence=ConsumedThrough;未初始化時不要求 state table。任何這類檢查失敗都進入 Failed/CleanupUncertain,不能以 CompletedWithErrors 蓋過未結交易、未消耗 LOB 或 digest 不符。 + +摘要筆數核對才限定無錯誤的 native 完整結構匯出:在原本空的目標列出實際 user table 數並逐表 COUNT_BIG,對照 footer 表數/總筆數;這個核對步驟可取消,且要單獨顯示進度。資料型匯出或一般 T-SQL 沒有足以進行同樣比較的 manifest,無錯誤結果只聲明「所有批次執行完成,未提供資料內容核對」;已略過者維持帶錯誤結果與明確未通過完整核對的說明。 + +footer 是預期摘要,COUNT_BIG 比對也不是逐欄值/來源 DB 雜湊證明;不連正式來源庫做比較。來源 READ COMMITTED 的跨表不一致警告仍保留;因此最後外鍵建立可能失敗,不能自動改成 NOCHECK 或刪資料。帶錯誤時不給「完整還原通過」標示。 + +| 結果 | 顯示與證據 | +| --- | --- | +| Completed | 所有批次完成、無未結交易、必要檢查通過;明示實際完成了哪些核對 | +| CompletedWithErrors | 已遍歷整份檔案,但有失敗/略過;琥珀色,完整 log 路徑與統計 | +| Failed | 停止原因、最後確認批次、當前失敗/不確定批次與 cleanup 結果 | +| Cancelled | 已停止排程、command 已結束、session 已釋放;明示先前寫入可能保留 | +| CleanupUncertain | 無法確認當前結果/釋放狀態時明示仍有不確定性,不冒稱安全取消或還原完成 | + +## 8. 取消與生命週期 + +按取消後停止排程並顯示「正在停止匯入…」,向本次 SqlCommand 發出 Cancel;取消不是保證立即中斷。等待真正回應期間 UI 保持可回應,不能先把結果改成已取消,也不能開始另一輪匯入。 + +command 回應後,用本次 session 進行必要的未提交交易 cleanup(獨立 10 秒 timeout),釋放 command/reader/session/SSH owner/file handle 並完成 log。若 Cancel 10 秒內未得到回應,嘗試關閉本次擁有的連線;仍無法確認時進入 CleanupUncertain,保留工作識別與最後位置。不能 KILL 其他 session、在仍使用中的 worker 上二次執行,或以自動重連掩蓋狀態。 + +視窗關閉時若仍在跑,走同一取消流程並避免 callback 更新已 Dispose UI。沿用 export wizard 的 job generation/owned-resource 模式。取消可能等待伺服器 rollback;已提交部分不會自動撤銷。結束後「重新檢查匯入」回到預檢,不直接重跑失敗 batch,不自動刪除部分匯入物件。 + +## 9. 程式邊界 + +沿用 .NET Framework 4.7.2、WinForms、System.Data.SqlClient 及專案 MSBuild 工作流,不新增 WebView 或外部 sqlcmd 執行依賴。 + +- `Form1.MssqlImport.cs`:集中 MSSQL 檔案入口、明確目標與精靈啟動,既有其他引擎路由不變。 +- `MssqlImportWizardForm`:四步狀態、Punky、確認/取消/結果/bounded log UI。 +- `lib/MssqlImport`:分離 request/result/progress 模型、streaming lexer/preflight、owned-session sequential runner、error log 及 ETA estimator;核心流程可獨立測試。 +- 共用已有的連線擁有權與 Punky 控制,不擴大 `IDatabase` 公開契約,也不把新 reader 塞進舊 MySQL splitter。 + +以上是責任邊界,具體工作順序與測試安排於規格核准後列入實作計畫。 + +## 10. 驗收條件與目前證據 + +### 實作後必須取得的證據 + +1. Lexer:每種字串/identifier/註解內 GO、巢狀 comment、跨 buffer/UTF-8/UTF-16/CRLF、超大單行、EOF、GO n/SQLCMD 拒絕;預掃描錯誤時 DB 寫入數為零。 +2. 有界資源:相同批次形狀的 1 倍/10 倍大檔,無整檔 bytes/string/AST/batch list;含 32 MiB 邊界與大批次拒絕,峰值記憶體受批次界限控制且不隨檔案長度線性增加。 +3. 同 session:temp table、SET、IDENTITY_INSERT、跨 GO transaction;64 MiB binary、18 MiB Unicode、Geometry 分段匯入後以來源測試資料的 bytes/hash/SRID/NULL 及 metadata 比對。 +4. 錯誤:預設停止、勾選後一般錯誤繼續;交易內錯誤、XACT_ABORT、斷線、timeout、log IO、LOB chunk 遺失/重複/亂序、Geometry/XML 轉型及 final INSERT 約束失敗仍停止。當前部分寫入及未知結果不得被標為成功。 +5. Log/進度:所有 SqlError 落檔、UI 截段/完整路徑、故障 flush、byte 與批次 Int64、read-ahead 不提前算成功、ETA 暖機/長指令/索引/核對階段、取消與關閉生命週期。 +6. WinForms 與既有 smoke/Debug/Release build;測試執行檔依專案既有 smoke 入口,不重建先前被防毒隔離的 ReportExportTests.exe。 +7. 最後才對使用者授權的本機 SQL Server 2019/Transfer 執行實際 4.17 GiB 檔案試跑,保留耗時、峰值記憶體、log、物件/筆數及約束核對結果;失敗部分保留,清除/重跑前先呈現具體狀態,不自動破壞使用者 DB。 + +### 本次已取得的證據 + +- 提供檔案為 `C:\Users\johnho\Desktop\Transfer_dump_20261013_165730.sql`,4,478,414,151 bytes,UTF-8 無 BOM/CRLF;僅 bounded 首尾檢查,footer 預期 126 tables/3,247,785 rows,來源 READ COMMITTED。尚未完整掃描/執行此檔。 +- 本次研究時以 Windows 整合登入唯讀確認 `localhost` 解析為 `JOHN\MSSQL2019`,版本 15.0.2000.5,Transfer compatibility 150、ONLINE/READ_WRITE/FULL,當時 user tables/views/procedures 均為 0;具有 VIEW DEFINITION/CREATE TABLE/ALTER 基本權限。執行前須重新檢查,這不是未來狀態保證。 +- 目標 data/log 當時各 8 MiB、64 MiB 固定成長且位於 C 槽;目前 C 槽約 152.7 GiB 可用,D 槽約 2 GiB。來源位於 C,log 預設也位於 C;SQL 文字檔大小不能直接當作所需 DB/transaction log 空間,實際匯入須觀察增長。 +- 瀏覽器原型已驗證四步導覽、超大 batch 阻擋、預設不略過、勾選後模擬 SQL 547 繼續到帶錯誤完成、未勾時停止、1,283 筆只顯示最近 100、唯讀 textarea、log 示意操作、取消先停止中後取消、深淺色、640 px 無水平溢位與靜音切換。console warning/error 為 0。 +- 尚未實作 native importer、實際 log 落檔/DB 寫入、完整大檔還原、native UI/實際音訊聽感驗收;上述畫面證據不能取代這些驗收。 + +## 11. 主要技術依據 + +- [SQL Server GO](https://learn.microsoft.com/en-us/sql/t-sql/language-elements/sql-server-utilities-statements-go?view=sql-server-ver15):GO 是 client batch delimiter,不是可直接送給 SqlCommand 的 T-SQL;本版支援範圍另按本規格明訂。 +- [SqlCommand.Cancel](https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlcommand.cancel?view=netframework-4.8.1):取消是嘗試取消執行,不可把呼叫成功當作伺服器已停止。 +- [TRY…CATCH](https://learn.microsoft.com/en-us/sql/t-sql/language-elements/try-catch-transact-sql?view=sql-server-ver15):client attention/broken connection 不保證由 T-SQL CATCH 處理,cleanup 不可只靠腳本 CATCH。 +- 專案來源:`Form1.cs` 的 ImportSqlWithDialog/ImportSqlScript/SplitSqlScript;`MssqlLobScriptWriter` 的 Guarded/Consumed/Failed 協定;`MssqlSchemaScriptWriter`、`MssqlExportArtifact`、`ConnectionOpenService`、`MssqlOwnedSession` 與 export wizard/smoke tests。 diff --git a/docs/design/mssql-import/index.html b/docs/design/mssql-import/index.html new file mode 100644 index 0000000..52711b8 --- /dev/null +++ b/docs/design/mssql-import/index.html @@ -0,0 +1,149 @@ + + + + + +mySQLPunk · MSSQL 匯入精靈畫面原型 + + + + +
+
mySQLPunk/畫面原型 · 全程模擬
+ + + + +
+
+
匯入資料庫 · SQL Server
mySQLPunk
+
DATABASE IMPORT

資料庫匯入精靈

Transfer MSSQL
localhost → JOHN\MSSQL2019
+
1檔案與目標
2匯入檢查
3確認執行
4執行與結果
+
+ + + +
+
讀取與執行遇錯停止

正在匯入資料

dbo.TransferDetail · 明細資料(示意)

+
43%
已完成執行的檔案範圍1.79 / 4.17 GiB
已完成 928 個批次檔案預期 3,247,785 筆
正在執行批次 929 · 行 2,842,105–2,844,816
+
已經過
04:32
預估剩餘
約 6 分 10 秒
預估完成時間
—

依近期批次速度估算;索引、外鍵與結果核對的時間仍可能變動。

+
正在努力把資料放回家!批次依序執行,請稍等一下。
+
讀取與執行›建立索引與外鍵›結果檢查

目前處理佇列

表名與批次為示意

目前沒有錯誤 · 示意紀錄
+ +
+
+
+
+
互動原型 · 檔案摘要與目標識別作為畫面範例;執行進度、批次、錯誤與結果均為模擬。沿用匯出精靈與 Punky 素材
+ + + + + diff --git a/docs/design/mssql-import/snapshot/error-log-dark.jpg b/docs/design/mssql-import/snapshot/error-log-dark.jpg new file mode 100644 index 0000000000000000000000000000000000000000..75a2b62cdac398c1c1b6e4e45b7d96c9a72b06f8 GIT binary patch literal 114885 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

D(A)XDz1&;A-A(leyG_Tum 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 literal 0 HcmV?d00001 diff --git a/docs/design/mssql-import/snapshot/progress-light.jpg b/docs/design/mssql-import/snapshot/progress-light.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e7b4d3b44e419e5006a1b967b77fed29f52e54f GIT binary patch literal 106070 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 a#&ni~u9^zZ{ zJMd$DmsGMy+HzD*{I!)`jmVTM{%nDvI%Rg%-uZ9}wHdj|jC9j)65Z(8&XMerj3~3T zWygm<7HYIzj)fB0+_Gu+XmgXii0N?=I`}c7IeA$H%&xSljcZAgPn~KXURO$dE}F+U zul7%uI8=j#MbhJT%XME&H?dpQ0vkQ!A&@`Yy1r8yuJ`0 zf-~(}-6EP^{{g5qHShD-f0{Pdxb^nLa~W)*?T?tm)+Qw`bjyW+H=})!UQ9eRf5rL}YN5`v5|wKXNk#Ai+zh*C9lhVaB| z-T##DMJj2Okk20g%t+Vf58wvo_y=$#0P`ye!2g7hN#k?0bDzMwy8gx@thPCb2`9HG zjC-PSc(;ApOF#fLk#Xi+()xTD7_T$_tiebP=Zkqc05UYnpn2U;@IT-tlc>DC zS@PR4)JXYfuBnC<3Q#w4_n{3SL!nSjhp=5Fv`_CZpyBVb~beICIIWJ9Tj}!k@KTTR7r(| z)x#Gle;4|AecPrImSh`qt2Ev>>G|O69{`J5w$^dr#qP$Mp1}1ccsO+TF562I2HQvLhZs7Diu*akdFA*b55Yfg^8jZztD|3X`@!Y=3^bU2^18z~CFw{X5k+y3`oW7^VO(|A4TC^7!M# z#7lHIExgWi1is2z*0ZdsU##FkHiRK__$#7)9*}VSP<|vy*Za)+4--%Y+!zNvhTbJO z!1riSPLm|~Yb1A<<;(oqa6dd$lEhJASyf1sX&P3BK#TL?*sFvUJG<9r7cpOX08Nfg zzHgV6brne|hYO+#G|EU5hdJIi5aX^vcBwc08r~GVHE!jy2ni`OB=m08)_zu=ez!tC z+a2O?u})Rl$%5Ldnd99B4%|g0PmR8a$Xr$mDSPGR~>67Up~VIB;0*q6FD_LZ*ppd z?k|yL6d*n%AvMhf^)Q_kbTY+!g&l28)5$(VAI1i+`| z=6HGLxhkeQKen#-?)(zSR#72fbmiFz4`=SH%^Fp%oR88Fkg4Y8^azfKWAqT&3&zta^zl~UtO{cm3(^_a4SG$$nw^D&yhdopvPZi zv!x$2{#axCFhJSdqJl#{PN79%oGa#4LXi&??b0>w@#4TWud=x(iRrQ{?d)bth# z-M@}SWy;!omLZr`d|jFmczJo|AUrHVa2dh@uk)8!By6HeE?%f!mVR6R2lU}#{vmr3i69fGy^@)ymELY%Zoqrio3{L zL}TjcXS@#ZLUw7)KDZ6DzAIf^Lw|BaD85^*;e~=gxo!C@WdJ99J@lS1%SLFC9hil4+x#`G z&X`2Ch&dlEDMnJh#|v^J|0;u|u=A?zB1YWab(H|)wsJ2EJF8a*-dqhsK}Wi(TtntC0Ii=g#SOWxTCKqa$> z&(chw<_x`KiWYV;oz5x)`--*|*!5`+P2xvIp3EIt1B9^J)bF5W4lDPXWwm`bDKn7= zJAuveKfMUS5(R?Pn<8POw@-_t1+lX|G`lllbMlQ6v8C5bb?~`{F z=%gX?_$`Jm-CC}yfLKKQO~>AaaR;Jbwml?CN2tCD5Ep- z=jzo-&*jJn&h$Oq;=z>r-5_ZmHu4^10C;WM1%Iicr}@%l;W+tK+geFgUfV&@!Lxmn zbqTZrhZo~-`d=rnEE4SsN=r)0N(&YvC0_&1xDOlBW0U)=TZvdU;u&#xnA0Y}T07ie zh;52v~c zcuuUqmK|r46S<4Fr{B|+uXbmXuGv>>@yGQpZUb|}5+6H|RzgXM;>ye-6V@(i9`H5U zR*#;cHR!_iu66#$!?_AXzo74Oa^%^#Q&|9B2%QQ5280j`%9!W8F`H4W4`nale>1#W za@wi07~%Ie{#qtFUtL|1Ob!$z<-}+Apbo;!-J*sK)581E>oo<`vJQ=JKPen<{(W{? zX}FU*7hvdiFu%O=wsvN)?;z$2FvK&VFJxX8>GFF3J>JYD4@0Y~Giz5mLXY9vhQ-w- zf@tFH-e3>>Dp9fLU^)LFjaE-jZpbVsU@<^@#>`h`S?ft{t2@gNhfi}UTHhc$Pk8RO zCRnlLDF(@TUznE+PwQD-i$Pr_D=M`NP)tAGgnYI`exBYH*-wP%z7p~vcbwjixpB?} zjuz|mDK{BsnDE+Er#KID!ku@SBN631#Q*+XTzDFg=V!mbl|3rH?~_k-3^}~ zzih%RE-KlF?Ot0{rJ#+@Wg_u=5eodL>?9O zrlub`Jer7eHxh5Vd;LQWMD*B#BcJM_-v95PsxcG0>74BntuSc(XKtnnZk;uGxg4;! zw7|!N4~MR*g3N{Ip$@5GL;m8SF)@gK*~8xm6U{Fv<8hlccyIB)nSVL$mvfNbvP;Nu z4NxFF<{xerP_(pMwg9~PwV^ZiTXSzPwl#W`w=81Qe^cO>+-&}&-qSY{xvFP+omWjh zSSMS=r0hB(eOkHQc9i4Mb|EeYPcC$1bqYX02#6l8tvqV{e51Ne^ER9Av+4hMz!jqZ*rHE5_9bRU#0m!C%B1gMg8eeB+RN?CR6 zebu;9U0WKJHmk4Q8IUWMagiebo*;~>`>EW3Cjy9-Z0IpG)#W1j5+Y-9q&1dBy_+az z&!{O3z7jiD>_=;cIjo<(3ya#Z`a&;AYNY@e(!Ldh2!jgx{zmcO&E7S zXFS#;szge-Pbd5-tH4vPqA#SLK*Op_)Wy=)hxpkSX*q z>HALqjb!5nY7q!IsYc#+FnSwVFDWzFq@1UD`|Q`}2e&W8 zX;aocCp?mgy@r^6RY9P8AAH10vNIMVGZends6KI{z%OjN*Wl0G^U^}qa^#1_vo|z4 zA=#H#)M{H)o}Lk@sQePp&KB2NRxT_X(ooep zGmTLudzN04Fb;$8t?k%P%uHD_nh}G6x=xm6N6*deDgtE>ES)V`eqElV;)zRz6$B7I zdFKJp^C_vQLekR@F==o`IgZ%L^wR> zlB-u1Ai2`g(v6bW9-tThm}=b~v0hrS7|BI$r@v=iOH;4T8JB#>o~sD)0k%d0e2E7L zl z)Vcs1j*Bl<46bD*^^059E~pf2pLf%h9mpnj-4Un>`6WHbEWMFzuiZ#mT-<^N^A%Ov za=4l#98W)qa{NR{=^=WyI4VcHUaT-G^w=PvR883&;Nb+@=Z59z=rGQ#w60TohX#rI z^V@VSmsC6)Pf?IE*0;ioSxu#8WYJU!*#r|>XT>;jfUlRnq6K5$hzzGT4U!z|KcK={ zDstII_ppWS-+fYRus(N z1+OKJs?tF5LLmv$Cyp6(QQ`Le=h8>8Fhto`>v&xu<(JI%Xk9~Qdpq$LnE#8t_l|1v z+4qH`pr~{yQbLg;Qi60s7wJWiUP6@`LJOfuqzDRv5SkPzq4y#!bd)B&hF%3i3st&+ z=w+X?_kGV<_n!U!?pp7A&%JA%f3nuhGnvUVPv)6#`FuXJ>8V#?02azB2T7_e*p))9 zI&LEhx48JH*jO8!AK{g-P%9S&OHMs6rOXFJq@1m*?tswxNVKGuaB%EAo}*M`Ahzqd zQfBfz-3G~8S%64G2NCOiXl9k(sEV4j_j=uv6bD6HHm>fdhp5(Vg0#z) zEo0|>FFYo$Yu0xu;jpWx*cNGv2uUrh2&-Viv{urV;6>RfE!>h157c3Q7#aCHOh&IO4l`rNcc%zwhz)2A-LA`~g%i z{{bu;)uyLb&TN_MI95X*b0J7v;}R3WX{M@@YK}zo0NgyS0ZoHCWb_60#r_2iAN2y8 zk+#^nz~CzCT-#fse#sWiX~y=raE=gkE!*=lQk$KTag~%IZ8C|r25ozDgF;G_`GiG2 z_awShl8;Hws~#^^*|M-<7-e?6fs(K@VgP8N6CDE?@o!0Qc7T18AINxym5_1GpFX z?~Bv1kdK8XrY>UJGQvf>)YKm-B-T|_G>Bh9;Q*(HnIua$GTe;{BOd>601gI^yCY^_ zg;D)X`>c;uoLWi?mQoQ_#{GuGhX;x-+b3>poh z{=}Tk7Qv_V_r>e=zr1+aP$r52hnd1(rMs6RhjfT*UVM|y33Hd(vNcYnq@-3N-oFW*$s;6SOUPRf*fx?+EjX=vSO z+XJ&+De}bpGu1GO9!l1Jwrduv$MGgL)bGM4RXx?N){`-xG*#>#Wdm* zBQ>Q+%Ramn_OzGNy`|*18;&kkt@Qxop{A7}IFDp3s(GV; zG>|g%t%d91hYeo2yxqKQx>_}8xI zI?V{ExwPA;1$&#KUC{&PilML%V^cWhnYW6T68P(Tr4~u>oQVCz&GRrlgx*t|3}^}j zqfQ$NwpdS#5|WcwG%6{n|JiICN9<3oUVde*+NLzWn9uN8rTNBr|M(rWFe1d3ec85Wq_`qs{6--Aq zSPF{vzY@)nEDf|c z)um*AY4vIFbyf}}d4Uy;y{$#m#I+?Cfk__k7mz{m?EajiJMp<+ zB6ZV<_U7&eoRVd6DZI7aJCT-NY6>MVqxmv`!O%8c?#4^rHK$?B5x8q{jk$~2ov%{G zx*MC`0XY%@Rhe$@+ZQzUQf*mEk+@*RwMXF1C@q`!65-AAM1-eHACz}6UnEUae3_&k zq914R#jdz_b*-2(aFPSOqRA9O0n$dsLt@z7^;uD%=-8mJC1^2rKTL1SHn?c4LSmm% z+`BIfNTLzE{3h2yvdV+e4J4{Ora_W$ZI+-Di4^fp41*nKT`JIl(uYGf43f>hb^KN< zh;FOX*CLpYAS+TwhkaU!ybVM1bd}GYQhKT|c{*Y-N8<9RGJhAFl&+XQs~^)Ts(?7a zt?sb>`?s|O+ql3@Vh7J34VrV>cerRc@j&a>5E2>8M(%*%6tAs^Ek1BhVBW1w4H4KV; z1Lu<1eqa+S0Df#cGb^5qx>!zLL+KPZLT~W-y7!x{-05M;FeIlDm#;M?8>=ne_HP_} z=H&2h0A_qPb~mR(^V&6hH)QSnuB}-}!E$m1TPvrcPxT`8eVkZVcSE`3X8HToFAAN> zHsb&g-O6n;k>Hzyi(-BeyL{25D!Hi59cdXfTPt?q6*cK z>4`Z0@R|pAMdA}99l%7<(o{iet@LVrTny~=P4*K{eC>spx*KwTtLK`{seExm{31Ji zeuT_e@`;P3_)jY962y@EvE8hI_lL_AUzrTFccXE=bc64{7){9QC@8o%D>qhdkbOcS z*uq1e#I`k`V=`@Ro8czjX<*9fO4|NgG>yCF@DM-z)_FKnp(62zG@xMff++&$*h&+05NKfnD>!i}48!UhFcQl;!cgnX)utV!@u zs6MVqJW`x$7#~i0#ZIWB%t6d5!nHuNOOon6i5 z#O%fRel5*@9`)26XmK{`F+X+cdbNoosiSSQH^YoEfOCk!Y;lCK$-sE2FwUpZFVW4O zhO^Wcpgvhy>ccPTV->Vh#}P+PqVQ;_ee15HiIMKC1WWUROy$6hUPOIQ_XE3b9e$2g z5(+SA|Lq)z*J0Nk>q7I8b~@YZxncen^;dUXlQDrSPg}{1&q(J|gAXP^j>Lr^kMC9b zA89Hk^oG_o7^{e(+{UWA^v+L%l;zuqZaKpw2FnHI!Gvdz&j$Ab-z=&t8bg`STZVr~ z^@{(!LjFIg?8gaZwf+?tbj~w+Lr1Vv>!D#Y(n|z&tY*xoX>eiyQ4wY0eMv3i?4}mG z14pd+_S;x5jfO6F9-Kd?15TLDKiWwss#uoOJK2Ok-8XD9Vz-)UiX6_3s8Ax#o$qU1 zzt-J+aPuiEW&B)67?5|?9=I*%QC^PbX;dpJX8ij|{i<#Bz*p2LPJ9;_-XF4>{n|6w zNN22dGo=r1o(QhW@!r6_xkaD-%Nubx4!GzN8z zbkdn6c;k+e5B4wcTQGx<+`sLwpL!6ECU~tu=G10Q32-Wm_ zF_9XXwGBEq0Z;spXQ((G?xO><{fyXqHPHG5p;nrtnyIkn{_mvc!06P4~E42Ab~8(K%sKM~;>< zv%4ookhj!gKUrk-_r`$E>)M9^IL8mbeWUTk7_q?1!Kw-GQ;OM;a8~##hZ|)Ed`0%; zaQWn2#MXM4{)id(yr~AzCN_*tT7_9<|5m`*A3(GdPWAyvn)kKluY$eT+PUt@6OmQ; znAtf4nqmmT<>*URweEJ}v(pw-LRBy0fbEUs-e}M;kP^N2CD6fd1`^mX66|wd&+YvV z8ElrQZ4Hq+ae?!Th>%LxpJ2K#uH3E0j@Gg;GgIS=rVyT=M17mPB63bwN?FkHs_)z^ zE_v##Q*S-+9^T9J7Cp4|Am>`^({4$q!!%(0fF;z#oS0VUXrbk2q8#b8qXm#Avl zyvnWcm|ES9dWvght-(O54%SEquAqk=3mGM4b@O6KrE8hyyzG=XHRE-$Vqt^l^rW`4 z>0t`lT3Mv@H?kU8N~#U9dPaJ(=vp*GiVsd-Pe7);t*1wtoZ{Xj{`6k=tt!*USxC`Z ziW%G(u=2~J6Y zJ{jVja_{TwZ^1ZYmdn;BgBEib=4(WPgzos5XwO!>?_%#0JlW&Q@M)i#u|vq#;w}|z zN}Gl9orYpAihHx~Hzb;*{hTJIFO(S{goA9YJ4GtMEz_i9;bKua_48SC8XplOQ?g?; z{0EpfRbwg?FoN&QzhxAaJ(KQtg*7ZkO2D2ia#p^OO}Ufv0RfWD(S9)`{A>f*u)NpH z+5Mq9{k4}9VF;>m$E6An(J|8B3K1DhZ!rp@vkL{AK|0XyyM$wts8GhoDp&@S0cH5< z%SY^}#^U1RU%-uywFlrc(cgan+s0L0T751`n4LmYzOmiIaxc%ln?BDo_g3Fa0pf_0 zf#$gl^Up?3y(M3X%{Ejj59&|oS8ql{4I>$;W^J)uxUx$YCAvwGy$D2E>ry1bHU69F=#E`}XcbQHX*X8Qcr({ANH8k@wF?NA zeWUpF}{Ngn~7L3&TJz>;-@*6f`x`X_uBO;R{B0BRv{;+-pTg^CZa<-gzJK7Z^VWgJkDVX;j05emELrb3T3l{;wdQIxW4O1_MY>TE5&% z60wr$ASb8?Tm3RLr>z(UNi4h_zl`Uzd0Z4)=P>P(Qavu_N32QmsQ~o)9hMgT!$M1T zt%?ogHRLi~69!X&5lzaz5z7wP4{$UXnXaQeTE=Jie^>w}!w z@Etuq{|kn`R0B=1nNOr5_%SGi_tu$8TN038lzhB)MSl=pVqKYeGhu+}^LmEKY{M1+k$2 zuR$!vbr>0$+8K|Zf>c`B>Up=nowZ!^silQq#w4X*H+cSFW1)m@xJkkyQp7=SIXnf? z5AJSo_J5c@q!lx?!S{Tz+?3H1L!t0BHo4RH)sQMneRoq`Wx*a$IgfUBT-?#I456fW zXv$s`o6dTJ{~-4M{I@8n4tACMcM15ROMZA?>62`SJB>Cn&h9CF=H$7;4ZT?U`L*mx zm#n()84B*13u9uXx}NVNv2hzJ&GrmzZCoG*g%59}-_sjODb(!eRdhgX^ZY$0gnG59 z-B5=0s$D%=#*C#gn>}4b&2PTJPDvqMVt)V+EHY98Mx&*V=l^!6>DRyCR4D_N*Fc-R ziT_Srqi4{@cYomYtM`xgc{)=>{AE^m7(YAM$xSuhH7hay4az#vNLnw+NkEL7gUs=x zN_?i`PLv6(KJZ!TT*XBj}1~f=!4Isn%qB4KYthysQz~IUL zwe-Qce{_{Ou`4s)!M+L7ifvaBSIA0k6l^4eS&YnwZGpJr-Is32IEekOc671{jnNye zRqqZFsrjBeJ{{8O7c|0>t_3{@Dp;Zv#Ai}d1JxW5@z>q<8(=K9RwME?^4Ot8c&q#U zFBpXtqJelD9JG~`;{e0$9(5|}DE=i2?1l=6%O0oKD@qBF8VQp>5?V&-Im{h5O|r^W_KqwU)b#NV|T6-(3&0K&>!#gjV@b z!xGWLSt;knrTnhBCnhq}j+0twNukNLt`mGP43#sw_41L6;U*2o|u;bH>jyqwQu#_Q~#N=LmA_4j@DR^H*SDJwKVku6c06U4D6lsjhzdI|D zoJ;mAp?&0g1tUAc*(*_u*h{59qH0ujtrfla*p_4| zGjpw+JGFEuaZMoS(m><{4c~WHP`NSiE-nPyDI#tUIc@*uK7(Tqq1V$1Yu#WTbXlJE zEvZ#`u5{~`i)ed7f{5@p9j$}JUaF9kfFA`fC~1VG1sl4wS&5+Xx{o{U=Itcp6g}=X zL{~;J{}2dP)VaSIecznr)w*1E!u5$#w32@S9;i{LqR*f5cHT8$CFGZ>b$si`Y5a~bwLPZxp>;S$N}ej}jG zzB!vJL3#{4K}GquT=1!*Z}ah!nKdICeu+(7y6cDhub6Q!abl9=8XYAOtQy7WV{54E zL0;!JEVZpc0^}{&N)^;FG`tgacxSh2(gcqyL@fj38lv;aV1(JvelXHz&fC@B->8Q! zHHrUi08cmEPySgJRlBSLN#9OQ&F|?ATfV;I{hkf^BRge7<@=y61{kuyKj4C>YrdZ> z#h+639H{a_byB*EVgI6mu>=!ZRov#78yAtCUCwRJHweRblBEwlJpAfAb)wb4JTeJ% z_+a{!AoKWoAg;fS_|Pu114piy4#=z@x2ssen4Vx)R=1$E)@CYI zE9Ymp+x;7WHzD1?hA8E!YRrqq#dDBUIf)=BArZRS67LZoC`w z6F>Mxl@rL)<|x0fjU^{J zq#G&Npc+37iHMyE4!Z8HRlj6qAUJGSg>_S?xXQOdzW(E>^X`&Hk!3h!+#a6Kvtx|v z%fE}y2`>$1o0RAjm#UbI4{G<&5`YhcB<7`5PsNYRj+p?36-XWqy_V6PQdMJB^|i(& zY7?|MFI>;e-M>vy{>f~u2@L^vt2^h+nYC8s$2pywYD0- zY?e2%!`Vet36#>S;@k*!SQT-3&&kv~^tPFsg~e{b zrr&0^Rw0Mc^}x?)?+qw)f$LdaeN`}<2Hg}C7LD!xZ4-y=vysZr!g`+KnmC6RUHFn_ zr^_D@8#drvlasO51!2<1p;k@X{J43{T{kbPhRR7b-VjK)`{BZdch0N|-+X_BFjjj#;OOiYr;G?&obf8E+_ZqiDNHNzU`22?pp?AKYfcM}-m8bC)M+xY zsJvH3DiEgyZb=xO;;2kbd#oZ)*HY46n;0wW>FdQxi)wrOhBhBvHUwy}KQ|Z)kMIuF z9F1rEDo}cF>vp&hcKJkve6<8+LQG(;d&OSa5v1R*ksCafgbc_1Ecz5iBAmRW;>eRH zObaS(G3K#G&%i%56%dIK#f|N;H_aPaRrq;?p1Bp)?3Q8T$Ht?^)(V#M3f^$GbfBND z2S&XM#m#sghtkXZMM9l0P%Ql?$0=aoOU6Y2j z$Zp6U^l!DVFMiyox%9%DGNoiClttV_g_DurjuU3@-ERe7B(ctrmXyuN6Ic>DG_6fQdKY=IOQ#Bxl@3)~}!{4zpq^hNSNSYqi zu0|5uM&{NT%vRN9jjAZ8T4j`wRZ9q->c^rHB1S3IPDaHA5y2dM;@{T*?Ko6-y za5+m&lY#8WLI%jQ=|W5`F?`Yes2}n}p5v74sTH8)3xusG6ID){{FwrZlSkzMGj$N7_tae7q!9SPGD6meED!i&V0x{vfh9Z-uYcKkc@2F`! zJ!(x~C9^Qj`huC20ubY_o2%qD#B5~r)+>NBnlUj(?DcER8s|cvfSLTFGd2WPMm}|4 zA#w%h;`~J}byN-uED{{9cO3$2#zlj)} z7S}uBAJI8iO6jRFWu$!5GnjY`QjG44z&XeWTwT?Sam4IKSeMB8*!wURSx%>+ExdcEOf2Y&l)@`}f_k zBr%}gqrihSW;k0><29$WjE-XGphGDxuQPj*>JL@m=Kag#mND_s)G1O z(Y}Oen2!Fy9DL?7&8LaN1FQ&T~@3-S}lONz#HSj}7z zJ3m3J(1XUBO)wTQ2*)zNPIF9ypLQS*hkJy9WRMTiaox24sn~+_CHa_4SM) zB*wXW7gX@eOm3UFZZhE7T4*{nQ?QqVy2!0ugQ1Mgzf_+TTz!wL&&{!Tw{i^1G~kLW zEY{|Tjr#}V)f6IY{T+6G%eztrbCd1y9nAC6FD^>8IG~hV6?0Rbr~F>wNt*twWgM|c zv+WW9@ylYZIB-^WI?%V}S})5X@a(e^zA4(g<4E$@X`(>8Z#i;f9z!>f*C|;A(zD%9 z)$yqBB^z-LE8>PwBAsL$XtWAe0fT(>^n_{GvcWB8^R*jxE-jA@cWLsuxxK=(@y?!Q zprQOtA|3ZOhNnZmHaz;rke5n1JD+n~GMaWyX#6L)?P@0V1zL`E%^xDO=_Nfpz==ys zLCWsF?^4QVKOnpfcVE{S=$c#AT_X(|K?)XAlHilgC$3My-4ikHsrJO7uO7(GEYvq! zu7)y5Jx`SEb22i=SBeza~FJVkc9ch}t*zS=m^q3S9HctzdK(#x zJw0;eseN|jfXW|a-0_;A!1j8@HN=XcRT^e)y`>7RY{b}-4ZLG}Vz1}AEi4b4a`99U?uX=0@^2BdBqL|^0PE!$Vjj=#LL{96yMr3m9Fc4tI$gw~c@j?IC zq{i!7VAs28p$p7bT)en#OA4|YFB;0(1{~QdT?jOhCbH~{bJaCim-V6eAPqEp0+MnGWzZdb|fvrl<;4Yh~2LVv(H^xrH zwkFC!_Q$2do%itgLpfc~up{JJrSE+i zWOgvDByrf{1{lLo%fsi&*Ov!E<2J9PG{bi5uG@h4#t(!e$Q#rTGvs}et&;Cr7w_-#*%!Z zPlRvSg*z*7?0*1?dyJ#gQ}L&&zov%1B#T9$hw)C|ysM-e^Ld`{ss;Vpv7RB7Ils{n z?Q5xs)tXH)F0gu7B_MrMKv~()f#HL3-y?fwJYt?CnG~q-di?zd(6wSFCQvP~GKuBz z4`AMDmi9CL$*B zZKkX9`PqRV?FdhNum1IZsoMLGEwb$YkrtbMLrKlRl9#g8$g=15tQeh|>%vJ*YLMgvt?=I zdZq8vH2C`nJP`%n9YRbu;(&s}{RPhN<{bIcpImlV%VsZZ&i?^)cN=^eDzjuI1$VqU zn%Fao$2wnfdCsN!qZs|G?lH&e82C4;xIz&ZQsReCXHvspty1la6_cZBTTr}|Ox>5p zX1%#Gp#?H#) z;n&ASwUF*Ix%SAbk>(fALD(fh;wrFtb|i3R5G2tr7$^vz4FFIh0M3g4IlMW8|YVl(J&*;cTkVxt_kXiG-cys*FkiI zdBhD0tBB-WlRGECC{F71ahh3b=HO{VEeD%KY1hISNoZ8G~&K`W> z-DH9Na^;K8Z6Gs*QEWUY>E60OejNlpBtrh8vXz8^CZ8p=#5Hq=>! zg}EU{uFt53wp~nq4uvj2GeZ+oc>El5LhmHAqrkJ*>h>hJgTMeH5`J-f?Tq`}WhaEo zI#sqLFAi@if*BB|#TSGb`c+ANZu^#_f$^$**Zkc(<%oGuXME>$Xkwm!q7=a%J}B@_ z`!Ud`X?LyzEJcWEtROOi=%Z2IdY7LaK2CnQmwNKLytrYqb5QC$ZDpU>ivj>ZNXo;_ zDlet$q<{46*pKM#8umlnJflXLY~|NJae4pHuo#FD&TAVS0^`_&N3Ou_7ftZNP zW)L!*S-3yNkXqJ`3oJ=N1=k|2atq&lMnCN+N}Ua>tg09H`z3;T%iI-NsU}}(6n<(l zaf0Nn_&60y{h9Wwj^H^`qej?|YizQ^_tXj33-Pd_{(MDjueHA>vR=fA9d(!*p8LKCibR?~i1K}wn>b+j3+J(Yt77DHiQFZgDzdLX zy?;2HFko!GP=1SjgRe4EZ6S*6pJzTK)IOePjeNiR+4jbOr>py-BsYNl{#q-3`=)0a zZ>uo|g3cv|Bx50mFDMgOSX;_j}m;nGXF5Do8e@jkL^;esjAqXDTWs{QqjuQPWJg zkBkl)=w4BDV$YiDZ0BG0I$q=(XL0f8Jy({){|LsA8Br<+M-BmWFphfi+XSqo)*WFGT1^HDqH4} z|DD=M%0+mMvbL<;{$M_3X+`+N{b%WJwZn37so2U`(-T370iQc-MDZ;{K>7WiUDJMO z-YjnvCy-2rRYMFHy>GqmcsWeoVgy>r*2{O0ejx7in2WHX8GQMZyqWL|)c1X(>w~RX z9vpbmv4h*4=hQE!r;UW^>A|mv6YF97lKU|1E zFSXOlPs-72@-WOAyXz)D^lanwUL87#eUC@%79+33zh z2VX5t{PA-cB?T?XX5yMIVib{(wnxW2yM0oXaC~G-H;Tw(vzF0+Wss?O&Ed92)L^tH zkujD|qT-B9%V%<=2H9i@Vk~&Aqt|!-!Reu!{xw@M^o+%aeC?6ycn9|!RllV(6Wiw; zHwC6#x{ihiR<_9McOcBz*d!h*Xwc=?aJ3KLH>{(~_c&->r3j>nd*x+DnnsDW25hl3 zFSf@LkGYDUd?L&=%m3tX& zT@|z)e0)vyX(+>(6y2qPNckOJ&gwbkIplX(OLea4hO{|KFe6tgI)Da+V8nPME)w1; zDnB!Iw{@Thh}rqcOQq%4=(}Z83+b5lcG}@dS%zrnQBq@+W}tLy^W>bTDmndYocnez z*f9gKR}if>fgXNXO=Or&9q%%+=x)?~V^{uBdA+b_N8NBPo3JM7$zJBvLRkgoHRgqy<0=JaDF{aw@=}Nt+TBNemmw&w8iXzr&IG7BJhEQbS1(`ZHwU?0wkyG z;dr;>`-=2oBak3mGBt<@7$lUP;RvcQYb2~z=kcnQzQX|`^Nu8yZwx$O-(4Oe3W&@!`2oNES?IPGyHQ(qV6u( z;JABwg9Cxauhpk*OWy~sh#wgLEM#J$k#gFaedMg^{F%cG%|H;n=#d$h^5(0QSApa1 zKorX$q7R;dn90dYM2kvjUhTv-w2yw9F~FL!6(tKvZ=`gN5Hp!OC+SKZ{WUbUihvxczkKeRF2|7k6=IOPSG~Y zWjO(J=^wyx(GXCj8Sq=~u>B(SQhhKZ__`a3WRjy@G%OpNq`yuzFjYVBrCQ;c9N)rU8}bpsM;?`?lG# zPY~}N&rU(rZndwS2m2P3yP(lo&#+I=wMenri;x53=aB_8b82q+>?NGe&*gLw9!(ji zQ8NX@w%JYCx-!k(j_!tOkQ^d4`XUKh<(r0Y$J>8P!?83I}oFbVI051`V?*6)Q z*=ng}S`d0t?MZWAv`WcD1Bims6Y0sbuNb9DuL~`Z8`52+SC8TD)usC8MWC`D%;&w= z;ER=dkvIG(8n-L$YfA>4cv~}osX~_>JtthA+hk!GYSSFTatD$WEM|8S_?iVxI*#(!G@_2$|%Jh-`dS zh3%&+ZEz6ts+ip66xE!4H1R|u?%B~JI>r{(hIuUjNMe_mTt~Rr$-XG{!v=CK06DJ_ zyuf#hn#PfFklTEu?GRljl|+_dkF6l(ETo% zqcPLjm8NYf)61+fWA52fr5|AmGLwqF(Oqfg5{W`xiee7r0d*@;O<7U!>eYsY)sR7D zcGAZOR8j%sM}fDq;O`ywIA6(&g<2hWas-TC%(w*%=!umIAB|-W`!|<_^2F(714)Cs9SN1zmPi{@^kEY9LlVRsUL|nDcGF zeCUP@>kZTuN13p&hDJI&EO~ORa)OK%P3n6wrF#6NLZk`#+Dm3V+s`SP`*2;n*cO13 z*e4+R{>@Ru&3Tlrm@&Fw#L@I??$_!5=<~omQ6kov=vj#N&-%d02X3WT(ChQQSL;Ln zhdmgsru^4%(FmsM1`W~OaW5Y={P$a1(|s^!9f8_x(i7o<{eF@+*($1o)`Rx>qF;F* zj_%0x`98twjD64fEd1S76OEnhe0~d@n6;t;Wo*?fb1>=FdPF*w&gsQry6{cdY))Ys za^lj5Q|vAGmsJ0NEOymzw7HJz6u9|L&%MP#B^@TQ)U5K}GqENlq^&hF{lk=~ z+-dAqFTd3ED-|VqzWc5z563NyyTy^rW`5;1HECUUpfdiWRGxm+8xVy5v+ zNxL-s+rcyJyDI+7+*Yx{^h~^U&&dMHz&^&!!Nm1e&Pa!Vl9{rsdTrm@dz&B{1FbA7 z%!IzEAPN#fz{JR~`!t-S;9)YHo`1(NwM94W(xs3qXQsGFEbfS@eNNP+Vvxo_T1Os0 zQ@Ia+bEK4)qtXAKR02_Dcv~amEYO~3OH4QWo_TuN*W{w&IWca0rXb)~*Z#3+;2G(bJZ%^nuk*wP}!-a)zIL6s5-M2D6rs#v?hvLKF<$?j*h5 zi6XcMUy{7Pl-RRV=}dMjUYH_Y(CZ1aqcGp5oi(AMDt)GqDH2ap2)mm5L{SSTm8YfJ zb26MKMjmf5r)}<+ndtff91)j02FpqBN-uTR!g9iLVc#eCC7W*FbUyJO8oPKgdr!m8 zAfKnW*wkfJkyPl=f;l&+W;)vpT> zXd%6j*N1#%72&h8LmR4|8-Q){(g#qwu$36sA1gLnqC*@aK#_U}dUKHOPh9M1!wxK+ z5hD;AHx?`;g}Te4!;R9{gk%`CZ)q@XsmIMajF}}Laepp^hv`#_>)DY$K~(%Ai6k|X zCmuKi5V$&A5V9!h~H@TJ`Cdsi&{dwN2J~5kQBNLhWltmjJZUljeT>=vAy-J zORRllJ~1&q(uOlPWDjgamj7n{``u6G6zTnahpu>A3qY$RVo{_F`ksm(Zr4@*w~~n7ThZ1@3`ah zNYvS9PssEW*Vb^E{ZI6@6w>A)Qciuka?u^ULG5A@e1*hMOa*EaMdJ5Eh;H|FK(bn52^VaLZY0}EM*?3%{D}KanU0Vf)cCa%JIM8%TEoAP(NCSQaTFQaT@(BNsWii1g^T|8c9e!HEx9Rj z`Q73N#1EA2hS+mwF4EHKR;J8Fq6$}ps`*z9W$Qq7(uxX9O&wb4Pu=%+FFsaYW3K-I zoEFGuYy#t{h1!8|j--n$)N{_9v!1sp!!#4kiTIl{E4$EO%1i_Dos zHHCUclSHEl-<*NeQWWc-C3lU zu1s&9Co&`jdYKTX=I+nSwp?eHF1bJC13*D?! zb4;b-93F-*VNDTc9Jo&;DLf4ypm6s+138SGlv8aEB?e~;Y}$uu%q;?i0>`WB%tJ5> zRt1UW;wnA`jxc_Glz^7%wII^G!&j8=XOcB4>6W9&Zi@4L$6Bpo)Ub^54nwM)LSab` z!762!glzxp(~G%%)1EhjL#9jc;5%)^Tk7UXMFsT?eY5c%c!~&~NzKV5eTB<%IDkkZ z7Y*(uj6@TYTW+?avZ)l<)2t&YRSZWjj8oJ0axYw18eieUNZ@!BMoCc8N1X5W@RVt- z>E-i)vSby9uXBOwT{X?0W+&rDM&mRpRHhQD{A3xQn^cQ<)(qIiP2H|vPRSSKG>Z*u zQd>ahNY*pCsLWTU(o}nS`<8&tw!rD?Gi2+vY{V<9TR8N?f;AF{aMpLV7PX6G)#Ia$ z+a?-{*u|ovfUsttS^?tsm%(ciuM~2xF)BrN_*1_KF)Blcdd>X=kaMVRApV>c8S-pO zEPgZ(b)@?969IR|5Lf5O808+_`uFQ2ABfFlGrYwl`;wh_c;-k<73^GizpCQWjok!@ z$X*{B&QyGfaYj1!es?UifiNBm#>f7fMg)&CF}ebz@`EX!QH+v-CLU!Q$6mxU$gytDNZ)ks08}HP$ z@N-mue_5omnc$g|niD5~=v{kI__w**2aW`1C`a7jP4k?KW0}_j0xy0|BJ3EM{L7aW#3_q9$s<}Z4Il>@ z)|T!TTYqN#+l#AF-Nk1FCy`6PfKAqNPC&1fA1Q|><9c)sUZ89KyjFz->fq#^zNVL` zGX4*sd68_#ohfIf)}<74J4ue{6)l67L|yd{xk1>-zzF1)g(sRX1_3qVbJ9~W6@|~2 zN;@Hm9vvE0)pRRqb+irhCowgW`N5 z2H!ZbR`pEA_!L7~TqE{Xg$~9GVMw4Ha$ncEe0*5#1xHqKVq&34lqMM5&C+1!?Jb{Q z8&jh?RijFO914E3zgn3pTqR`Y&pP+`@hqOZiY6Q1OtReW){7!pF790sMm(PX1tzcFKB;i6NT*PH7iZi3pU!bNNQ$NaSw`C zMwR{=alYG8*~KV>&tBUkz@1_cX(0}SX@`bag^=HkvC?}}4PXBG zl(C@qqw`9HLGt=+rg5J)8Y6 z;Kk*g=8DrenugV=Sn=RN!ABzY_o;L-Aj-}kOv}3$QQ=7uW4nG*ZY+h_jc)M3)49^$ zOxMDw*u}^9*>_l1E?;%5BV~CXL|&T`TkQP>OuB7xQ1+Ei-SFxeojoBDMkeOvT{F_E zSVlZ_vT343E^#h|ELXsuFq!EVrPD`y^AC$4e{3>DRym)Nsp-@c;BqwOk z!Y;acix)_+%azi;nQcS+PO|NoXtFp`7S$)|h;W6Si%Jl?g0Chu{oJT>;x9Si3}O}t z!D}_1g{U(T1!{2{9M zOU3siMo5{q{i7>(mvNA&hr<6K7m?Q zif_DJl*EfB?^3@(kn0O?TqI``a<_j5@#;Kb`ELo$95k`;r}H)&M%L` zLLWp`iERIY){Bcvc0knLa+5OPU_|}`^$R1KsfwehY;r#qKaF3{q#qxeoMC2*MB$Y|+ZaB| z40b=5pztL2^41re6_y0A<>SAsS=26aWW-6hFd?4zmX<|g<%586z_q@;Yn0*`jauYM zzM5sdnDUF#aM`CZzuszxR18j-%qXNmLIfJnON9}Tr0K0$RgOL;)Ku8F??3)6_s?Cq zBa8-VoCeE_5Rs&&eOIXQuz)gqG=Y9SalTp}e2MpOqhM)bfk9wL02t1A?pE9i3Aa7OYs*F_Url=zTDNse8yKi3hJ3h@+APe zm>H5#?wm>JeNL>TVR&Fi_k9YENxIWyd`qI(e$iMhELZ{=Ec5-E&m-x7Dg@C1I$NVg zoX8TWm0n@5d%FwcF+)9e*N8My>_sl_ucA};pl*8@7k z3-3cICdsLJwa&L1JEvPhjS4!2yQmlWH3wne)+8B_-i0Bm75vsvOTF z*uRxO0R0Iv;4*L4)6yB+hi)^6eKev+x^LNcDFm!?ZzN9D9AMl>DNx@9)v9%|?Pg~1 z5cXJA`|Y=o158T^dEfNb?$}=W+zj-S@>7(cI9}IG=aqiz<%wXarH#^?b*2=loQD-W zsSWdxgf0vG`9^iw*vSW`r0lQT(Mn z`XM{=pVH8IsX&2Tr~0*zv}=SC>A@9#k4-$kTifN%7{gWJ5TP+*a2@N1zW~CZ7|fx* zxN7zIBj+0fR{2H`@lRE!uiZ^gE`8Q^*K@0+!rka-b#e$I>>kEA7vZrK@Bac4X=>kH z6qEkYLr3>Kx)JxO0xeh9?dp8MP3v8R;+HrD^BHfnaUR_GmB$+mmz+eT_SVZMclbZ{ z^RWNt{ReDpxA*PX4 zc`%pEIdy$*9V>eI<&dp;mQ7he#Y?w;`I2Il7_Xy_y!*k3+$%$0u{XEVtL8X5CDiTm zcuOZ5Y{aFV#kQI9w?vegJM_-ucw${=wB;OKTZu#HTL><=e~>=K19W)c-}CorZ=u9C zs3G^F`8Gm`i?OoV5yZuw&2c=s@}G-LqBlgwDabj<*Xv1BUc+8{hL2)mXMzNSw&v0w zKvDGp167vudUiQwD0xzM6imR=c?QrP;wRPkI*SS~8#EZ~^uF3ZI)!(uxB0tli8 zAR_Ljzg4w(mKDHQ^>ZCm#r?kLOF1Chj5~f^G7|c7|IDu+u3?p@wt%LJ7XKVGCFHWwp_c>StwC*s2K4GMGJ#SRFP|JvkiIWs*mA`-(O7Et>0L@$f#7wuk zAy~ASMdqi~F0g2S8C+;T|MS|pl;g>oduhYf8-I_tk9B0ar-{hG!&riq{T0l?u5qKS zpZRFNVzg8v>{b-uUhANrd-#eZ9*OiGHnORysbA{eksRI`$lYkwU7o0X227 zeiBlY^~&0BRHh>@wy-*swze_|Vp4sCU zg*$SoJ1ebnENv?T;l@h3;rA{?tIEZXh;hbM^NAfAd_oyL%Hc^^|?h9cG|UR=hoLwW59*kX6%Kt$PM$f3YSmT=|?ntPAMf@C^72 zXIo*Nl(K{Oi~V~SUcymIeg@<{hO9;XuYblBsuF#^jhPd01ugwpJ=&!u`ZDARv3~i@ z@+`^WXBKUl7gvDX0g$w7vg;gtE%xJ=0W*l4c3EcPtTM`e+w&H^re#rvZr9K~)2Z|Y zzaz|ohP`ixC9V)7DFoBf*7p6JY7;z-uYC7X=Csu`SmCO}?9L(7(Hm9`goNzu!8iI* z!F`H~Kp}x|z4;tyaK(>%K7=bsGg zkfmX?%~58#^Lay~b(tsp(}|DYf#7ZQsDy6R`&q;2N~P#wh#4M=Fqa?u90 z4v~|CH#+!#g-)QB*)=+Dn7|j_(+J8z$&UU*uixLr{Hhxj=9T9Kff_wiG4O!mIz=+i zk^Oy9I+G6i3|*`|*A#0XolzDuzexSJsol``q#iOxMO=G#`|PGAY8{m9X_K8s1R9h} z;fT=g%_CvJdZJ*)qjS==9RHL9qprsp3BG<=fsD75YZO+{j=|rPJFBxXkGY4|id=6z1tX=G~eOmAXaWBv*f zK;_Q=FdQ1k&~oQq%_6LocBB2H335bJ+k7wKDb+}g61#;xIc@7M%L0}8*FyMabLZ0w z_ZV#)!#+3LuO3%ymoR(M@Wj{|NN$Cp!q33lFI||PAv&%*VfW#OJ z+b1*G**z;%#I_Vf_$a6SEF*6#gQ z)Lzz)a1rt=cE!b1UKR+cLEej9I>#{UjhO76QVoYYsMPdM5^uZm5E8+9I4?BKQ@u?K z=g$g5kGR;N;b@vT6D^|BE&zgoSlV3M%JiKbtw-gg$?ByrU-JvUO8$fc)f)AsYI=E7 zmg!4cE_Oe5KXc2kmBf#BS0Tv~;WtEs|6KlbAyW(f3#fhxPMc6QVI8RsiGc0^8QD>9 zUkIc^Bx*YAQ5c)&(|s?$l^lc~Ta)2IC>SP=eF~-m<(*6ooSdSwh1MC zlp2nq#Jn>+gSQ&`CRewzfYHiy45tyKfx=q_2xP!{+rl^_ZcpVmzVYENKrd?M;o{cR z+2Io@WvOyy=m)~(pJhKisF!maft#z)56wSQyR_S%{>)AN8Nok#NL*bVb6N6sOxu

>P9*>z96!aO}Y*zWw7jwKK;MK~Shf;PZWhvT);v-YtE<#ls+Gm{5nc#CV&P)5N^^ z4#=exdd94zVt4HM`L~Ei5)n1P?U=s+9b(E0UTdQ*%Lcm)^t70)s+>B5nKogLSAEP8 z@q+SI5=p|?p+wsR>NqCpUQqiE&WvWbqk6Pv?X5XRLzTrEN4OsTgt%V) zR=l`46q^<7%BpjzDSGf6zFlk`n}v3MooL{IPerz3=Nn#MpktAAN?1ZL zS1Qnux8b$;L(?;xnrF06&GKc5?SVnppqm}k)w`l#WbkL2svH{SM3C)?e9jZU@V-@H>{) z8(?)zSlO`RUxBF$lT2=-(`2&696Uk?&Bhp1whYiKYWWSWrR&4#Z%p7qA&W#Uq4I#fH7EhY$V za4QJfwHdw0-?qE)?v)B$)=uVPDIX4}&#TE*)j}pU&qGy~9uX&lIbHh5nG6`1D3%XeEJPqL7?`2+eN9%2J?&_L;fmaby`N9Ad7wLT7}j!w z2{T?p6vL|%rxraulp6w_^J0P@ZkP8BTf;e1e%1Dm0wW|^aJSHAuuJIBM3+A~YDx6T zx{&VA(qbn;P|xdogfqLYOo418H;?ujb`vUQ9o8Og`D`A6R)~=N88C^a%YEZ?-267f zkB=?KtUR&cAJHHF2;ZSNGH6aHar*I#Hp|YDs@@fY>jp=4-)s#^G#S@#T}0Ns{R?<% zs*%&a?Q7N~;AB2H9m$f$8#7Rp`C|*AG_|pX>mg%v`L^z|JGfU~(9p6o!2Pq5KZnDL;7U|!4);q1vpw24)Wgp7 z3cj!F6!6Wt&=a}jHO)Ce=TOV%uHQQsq0p6-s3c^|9~A8YVMsAkrfJ5rGWt5Kmjy7i zX<2zMdGYfHF;aq;Kc5aJh*@6}<%v6qLCvC_exyDtT{_r!)xQ`@uDSQC7+ zCDNOB;7j}|kN;Z)by&)yCqkzmBg&i5vh@e8CP%zh2u{Z44x%p1nV09 zLoxj%Z{_{sK`7I;DES)5{U#9N6yGTc#A_ zT9A!>?U#@B*iUn}7RF+$o9zBJMLaSqsx8lq44J6pELD7HxozW;7nd%+2wFlzO$kqP zhr2pqes$}_H|lLEDC@ZuOe3%uqut`uN&6R&^U5mwBQOlYq$8sm1SbtvuyQq}AElDo zaB?6WxFIR{Vro722Cn|8y%tEZ*zlQO;K^Gb+T9-0-+yFuYX8LV6ayTqH3+bFVeDrX?fyFJvtP6XqJ0P9=u%jh#;;>8S`(#h&MUi|c$Len0NJorK8h6# zI~S9Ve+b7sPbIOkw6&Tch3h#ggYDOoQXWbT9W6NC4xyZj2sfZJ>s2I2zp z57kjvzgb;_g8xWJQH&hZHM38zF_=8Aq?d%xpp)8_@SO*Pg6i;gsaq@L+SD0|#g?bS zF=@3273F}|)0n}n`(!QHr4WRvVw3sRqY8mq2nShHKP9MpJKY}@8Z%VBqA~wvWQ$w) zj%}?fQN;n+i`h@H4(}s47WNQGNybZFZ5K`q+?M_mhWhl%u<%w#Cp{h0tvpX$V#+UG zFTYUNJ?Ri-64y;#PhWd3=Sty$uZZYs(nTSwG|$DmWxJBdtQ!x{nRi)|FEZc8(&nmQR{*3D z>0zST`*8cE2=$n=`ib0OVtxB3)lj=3py!cU;Ap~9Lc=>W?*LB`3!|UtXJUz)Ir?*6 zk4jB>2F0H^Oa8)+(XZ;yq`v{@5iL@c&4_q&iDssVag55wuXCQsk+VS(*4ItueHmUQ zY&Wo^S_xNTtYookF&eAW*;ucKQKK1t-70Ow6n#-<;y(MZFgF_e1c;-*1dK;5xiC{# zNDL*cE3f)Tv9s-i+4s%ZL6|WA`&V2howj@aa^q-^QLHc(AHPu{>C_tQCs}E7+r?^= z1*|DCA{QQBaY+lxk%uJ6;Ua);RmRJcZu3+3`Oxb>% zp|+A{O^eZ;@C;5kGTp1`xmUN7Q9$s{r$fyr6ZgxAN*=!C-n3+|R-=>Q(BYTSC z>F#^s!~1n$3SHvYG=8~A{Po*PwVyP~Q~LJ8FDN@bG&0^G{; zxPkC_3vA^JBK0r8fP}H9U~{Fw+9=PnsO^Q_(?3T?Hw!YO?W;H2dnu}pb|_Asykhs{ zL{%~qGc9^R=Fivuux5p>2hNC!yDRKG#C2?a&||Fqo={nAC1;SjM>7q;tL?>Gzu{}E zgTZ@BJ%BZ{Sm%(LZyNPZ)@HAZRGkh*bIX;^>W`E^x{c(HD4a!`LIAjtcFRH_ZnJ+@nM#1V<<&zP_Z2)Wyo>#qOUeBH-T z*Gl9@%*2L?xobYQC+ui2B2QIh1c_OH6=YT7&BK;wz%XsI!TC%S8KUL&24A>D$W?j?rQy%+y+|TJ$L}kU(wU;Nl>BsD` z8vwi=j?{~Lg%H%;ZJw29o4o8dOP>QbR)WBi7?)!2X*7N;AD97H#nQ||Q?w^*MB3iU zb)O3lVS$Xs_o1p`FyQ?wS&g}3<#^u5kR`N;1A5zg%i(QxiDNQc*6T-7 zP&TV)*HY4ZMxrP8IUMWhwze$-sMNUQuROj+SXsBEStDG#pRodg;QVSX`O5nhN2XCF zk-(>V!gN9|HW8SHu!f46G;*2tFhCkLa=3J(S@CJ@3rkq=Z*|-6JbtX*<44BpA@w=@ zQ?8x@QYVF~Hjj-=aCgd#GGkMHjl)tW(Hzy3xzl8xh8v_$Cdqx4`Vw7q|L0)ouei0I zl^Eyj;@M{yQ{JQR;GjCFy2eAuq=}&@b?aGyFL}nqf|k5~?pajbnMK7X&3IbU$NO4K z9~-qVW2NuZpIPue;vR%z)_KGD$dpd5p%7g4fum#XBUbni7 z@7-%!ia^V1K5Q)^ovXq38r*DqRFf@RWYnb$7jc`g>uMG!$`mJ(B3Dy%)yqM=ucN*> zbh}03ntAebiyENz5<9o<_@2f^DVkt^?BS^UN9uviS^M|XX8Bus(fbAKpW6jtX?GOJ zB{9e9bEv95jR$@A=lR#R7q}PFo7fa7y`pNz1)II;9vnp1IK11VsUDV-w6&?~$HPEE zxnnY}TOIy*RSD5FIL<0p@QgM%qtT#>;03=f0^B;WS6!LzWYQu0>rj(2z60^1RGKRP z7diVNdtHX&DD|&BcE#tNlQ!GWZ#j+g`VL%O)+=j&zNIHaedl+t)*mwYhl?YF;#wZe z`~(CnZ-{CAlhnIQt4*CfT$^jp7aA=r%Dhs&WW)2P&hgwc?#kXiB*XhjhuJ}I7nW3B z^q`4}!*ST&i|n<D-JYec0FYXw za4af>({YhliGt?N20;)4kdURyi01KLwq81QGl{eE9J&(9PRvk+mU*lj9`CL^>;7|i zk^9?O42|q_gaFt0na&rdZs^_xn3?fpH7nG_maavzo=1M+p|R4Lcj8j3H%n!>(b6?G-2WyuWw7g~p9Z9v_y~7mo+2WZ^>RRH+#UP4 zGghZA2G{5I@bay+7qiRD$I*FTu^NKRd0&p-9_N-s-5r!#th3Ii)p%V+H*LXia7E*M z!{b1~3A&@7u5RR}s=(hy8y6Bp;4SoT=cGbz=X}b&+u+M7AKra79an zL{J?je8}K+#pKUxM{)D3u!7yJ(q)I#A`3n3Errq*q{rd@pnij}&Nka5*F5Xzd#h&z z-QX0)QhvYFjusR zeI2wKPePKpxGdDDC6#OS@Vu=RRpQtx%qdJLC+$8M20(~?;HeLGX(hu&y5CsT4{#)w zKlD?573qkAF_t)DbZH)UBt04?7Hn~2bBLa`Ewb|;6f^69O82<@ad}=G{;~h6E~l>A zVCaod=+j+$cUMuFML~LFSMQI+7KWrhT9vIJ-W7Y~yDe?CfH$v#Q6KO4Rth^lxsi!$ zAwA~oDx+2s)j9U+@f54aVJz?eX7TdNOIHm%u{5J1b3dxXL42U%p#ZbPwhbXC@3`z} z(rN6_a!-qy`7Er$F(EZkJYDGyAL|@JkU-9$HY7l?-OXV0Qw^^1wsyc9)fy{6v%bcTug-GWc@COdO4_(M8a z;mJ0GZfqc|;v*2^VQP9>-NXogtTdead(Za<&s}U%f6rXofmz|q%miw{4nPbFb{$1$ zxx~+sah|`gGq|eB0%d)I6*kd5Im4~c{igS=;;-+sAQEM;`BbdxTKc=ni}xEmr}ztM z{^e|8RcOd3gCYa!#Dg)Cb$F^0L7fX}MCmEj@0U}SWsU{NLwiTvO7ydr?nfGhL6P)@ zM)`Co$|TV$pik+C@3z}_1FTTgQ`rawgAd451^2JO%bAO)M*vr{KK1P2d+tXjMI5yF zjd!Etnv+^{YSz8M+0SkhcmQIW!uy4<3k&5eC8nFk-ZA4#?OGz=CG8q#R}0;%J%U1F zjXi~{NLRc?nQd|opsI(#Z6ndZWj8b(SF^8L`TEH$n|F3WVPSacI6m{j#2Vqgc7;;@ z>G3>XLL!p32WnPK6!F9vN6+I{JgYF*uWL!D*@N0A;DIub6ZHF{9@8TT%LNn^8T_`{ ztK%HOO;UqqHdU=Iso}0Io9SHnMF^JSY-N%Yw4|8~k<1;ex_U`43|9G_$>@EZcAYF` zmau}6`ApLiR8B|ulX4_-_>P;K_aeC&!4nVmY{&ay<^MZf5&s)N(+UIMhui30jzTVu zAJ$y`rH<8u(MgGtp{$aPe7A<{;4|(bF3NuT>rgvklX$a+9fnU#o=HnvCyxy|8hwtzzf(iz2^!(L;9EJj=MG zj2i85X^|N4$NFm-l!;6(I+`I^!EhDN$#Z{FQSr>=?cyR{hCD^Zq;r3nvoL_ zaPpU*P?URRUj)=g+Nb529Z{NaDJ{rADY1HT=j?;=_qYvftAA2e3b+_ZtCw(AG4`~P zS0U+Y5MwtAXK>N>F3Q7gzW=n`xp<3=#kkjv^gR@-{8}t*L0saVx7*%emUDc8Wr==< z-u|Hd_omS+PL+TTo-W@RVet}p@a`d*9flmNE0==$@A(l!$()(*`hx?qWP`aC14hh< zXBZms#+5qP9=%Z~$*i1imJ+-9k7fnb2&v;C+?${iOeOywqRsS``(Hq3N4un8gIpvn z;r`nB&re5J_V1p43?2=p@V$8!zVD1=mlEss;(LPih_J2qC#)U#xaV=8^XP@ORp!To z?lB*p<=Bq!=tl#Ekf4>8Lb_!ty}s2J{W1xa(?K>(l~_qY0=1$FcByrw?t{uYQ>;o= z@-kYw@dciduPAP!Q)y5~lJ-vJ9AK!Sw=02}yq=ic^0M68vth`YJ}$$+o_Bt94Z_g^ z0w1g(R$}Jrq0cxA-|{Z515xvt?iq^WhBG@Kom zMcrR2e@`qBuM~RyTpWhD0>{wtRF9iuD}C)RR7v`suUgw8ad4BuPda{zE_0PvS|aGr zn+V6VU($ezvW&9PjM#IE;DT}DDl+!)ilmKiiu?6BACv@3^8KqdTOai!c*q!V>{q2# z*w2pn%`+wOtIzgywOVmwizHF2dW=!8?zThsG{qy{#`z!5O_04yCZUCwoi^R>cz7xm z75ZhL3xZr)?n3h8Ue_*LN>qHiwhhCZqguv>13Q}{VB~NQ{^`Ak%d>6;*{PBjtl%<8 zlvM-^x&5DJX0Gi-D}gsh+2B8kCRR=qXeZ#C%=L#hQZ-JG_wQRlv{vP~M zc0RFEw|%k|Qt_Swf4dfli7K!ro^rb8^UP8~fb7bb5N&V3k$?=whOZJCwf7S5F)C1>HurEX|GPhb|)3DGTE-l1INT^VeV7WZ#tQYe`Dt z!gKV*h-C#CZ3sV`S#+!*Y5tkvNeiwlIwiYXwmS32s-cU9kX5H`CFvgI+*rMa5o`fo zrB2(NnW}XH2t{xYq~0j2-9^){=?$wwqxMLqm0hztN{Exn4Szl)|8fa-|hS;)s)&z;^_rFaM5t7fdYClS<%UU<;` z5Ib(-l$sZ^=2)StW~KucI*@l`O;Ki%Eho&rG8%f`f`Dkvh?fXpo5!KqA&J49`5HQ` z&g5G2xt|v4`xMnu4>aH{i%P=5_m0`KKBq6 ziGd>~(*ow3mA>UguWtk2tOoQ=R#bKwF?YZ621xb|gZzde){gPVl`_72mrnqK^Ru)2 znpZ^+Q;6Dfv9WIJ-LSYh4dM7`;Q^j#GUA|KjATP09{cfm5yZIAUn+O0D#+;kXOkXF zm1MQ~1^vg_io)5Hi(|F`B2f+BUm4nYr)BJ{>*agD*a`J`4BIO#pfvb~#!w=0@%{}o`b8unj#wFXb)p~H>lU#cJG9O>Z)r&s~~ z|1m2StNzbcBla3ROp3VQJSo8C=H%yT^B;JlB#pk8-_QAx={{PFvwnOtR{qL~;#P6j z{c!ZmOy29=*3qd{kU%$Kt4jo=s$9Uds-X@*BR!4BXFf)##~O*94eao)U(_-zPWc1c|ZI5~cswAGpg~$}Z9H zbTeE7&w|8LQ^+ZAiab5@&;xc&Sm7b+OEci!vlfJm*l(EKwZXuM8aF$?(#6mLsP^cc z=U!>b_cxVZP~DG=32!fEW70qf;={HJ{{F-Vtiidt36JVJxila%t{<37mj(D1%3@p* z8>YkJMNI3tr#ItstYxWM^Dmh$gDaTxax>#RdX2o*G-O}hih-hT^&TgtY@8$(TU-^k z2abNR0p>tszqDGTeshkf;W3!8|FP(a%AB4*DvcH0)vNpP{wKj=6A`n>ycG+5ar`?Q z8+=!yrgBxHvegrj71-DIM6`{BKai@M)_mpeD z#k6l5Jl4~dgHy@%vut)N9;?ta+*hj{MHwg)AbcIj#w^-ZgQ8bJQU}8*WA6?=MS36M zAKZJlX!Mq)yGH{2?W=FrHnmopyaWS70s?O^^%ivAFm2Q7lN#GZuWP-7FQ%;|ZYMDR zqUi$8osu}Cfn^`Lmt3EhCHd}sDzHL0gEra~o9ubne#8t_IJyhLMjYjPSGb)#&4X*QCoilT4kIJ!_1t!} zt%|-1I_^c4c!pF(2`0pRB;$_;-6MUqnX*#y5TPt9vws1Eui=<1)|hJ>63iE-+)OJ7j* z+odEjow+f62|E#JX2pmPRS_aM0th}T7PZ+h4y8h5LT4z&7il0W131(p|i zs3T|02HW8uln{!rC5{4~aS66b{gjjM|5vS`{HJ=SeCnGk)swn>kS84%vS#g7x*z}4 zeX+k;q;tQjX~;P#`#N$=-Q-t_ga1?)!q0q_XpFi@VwUl`nVfn~P(^cu?qc-iw;;Z= zh}w+6yUyFbKF^B~NRl|ag)?xJhu|90ehyQyC;7ar-Ti)77Tp4?L)SlZa)OR&UcKFe z&iZ1#hUuD9M$DLm zl5|h&89H^Q2{A-5LvyX(gc@Z5t)YzvI6{gvj&@6E@NV|=%qenkcee{=$U((p7*Rj= zD%5cgNp46Lr zv6&FpeKF_2ul3ZD8sLF><{f2pPeDP6D4iS3oVX!r@2E9vpOqhM?49-gYk4nuLAx(n zgE9?*RFY_AUbD31C}=Qy@uD~E|CRVEN2=1&*Q5S33?-fEM%|(iIcwY$b>%#&womh- zpwOABHPXjD-t}uL7I^kiRk_tOqP9F#=zz9sfG@h^kR-K7RXque{wVo5A|lH3pH)$M zDhSt${8S{mEX`$kVL+{P36bibZb_V$&R-{4^WMKuUkyXy%F zM~k{IsS)Wk=QIuS?g;O__aXP`A%`O#jM0r^Oe|y9;*uOWAU}h{M#fGGlP7D~RS6kM zJ}Fs1bMBVy1m#2^LEW@^dV3yJl5NJ%Rb3M^V{tN0V1mK^_kfM}5P{mS%--LNb#p5X zM)do8?VO(s>rA#j_i+r$t-yV&t{Al*aE_%Db$dcL3{=0Lx?_db-{Y~?;W?o5?G0%! zdsAWu*&58}tH`N+^y^a^op%V5M?hrRv^E@CqBBbd{ZSYh>9^u;lFb?kH#byBKD7;# zsA>;?NuRp60!vcu zQ~d}U?|*Npz`tH4xH`{$-b>#uyElY1{HFRjFI9oR1;3{p0HmD}B8lrQUB279RJ~iS z(U%8}KTbG~rt2c_x1|dqY*ts7u_KDTOaI!jsCI$%X?%jnA4+>!dQ~k@{5~qyw1x48 zg*fVQtPi7QpR=8_-ixJSduNKTV>tT}t~5+K@oKfMXz26E=^o-wl_d(|1u3bvo(6U- zGjz&%;i-mR6m#9CXObZ@0*e@-bQvp;a)NG*vmn%TYWrdMb5{>5y@*sFljrXH-OPNV zWb|9=3P{$pw4iQMM<}h{LB-??Ja_8_^Xn+-YQ4xB7o~B5(RM+LIt9*C>f0zSkSj6p zNZVk$`s!57iWtWvhSP|Y2nl9UZ&_K9v(~|fmi=7It8Y_q zJO%fB=|np-VzKKP81^GGkrjr%<)N>KK5qv>2W!GYvHzS4@4-#U@3Rnb$tEJXHVf@* z{ICJJ$J+O>X4x)JWG33L4KLLs@z>F8Z8agIT6T3qibk|n2MwyQBOyr%iecsnK7o|IhDXlhgAMkZ>AL_a&NzM;@t zf|Lm!dZ&iEv7&VVFVdzg`4o-8qyOf=|# zvlT_oP658_-6QITka$$9d;$SFheB;)&=Dfwg<)kvFd;$;l`Y@)3tPA(oAHkpG!RA z+XRCR1~?LziFn4_`iv#H8@ygvt=*~3T3XlO<&d}XeAU{^%IQ4gV{h9#=LC91&j6j7 zsTF|0t0}&zDbT$rS4Ia6xsNsNP*ri1zysEL{V@Z*I99B*5e%>4aDHFvWYK`P8VJSU z-jfY6+CFUC+}k7R-sKdNlav34W9_#X_W>5GZ<+S>g$1542%spr{hM-AfqGju~ZR%llf|hmLqYXy3nIKL>*%|UHcH#hb zQShJPyY2#!l#dquWVj0P#XRX%Kc<|DibV|q=g&ndDRp*DDemlhF$RXOh1_5Bf$>0z zrG0;>yzt>i6t0VpFy+LLcIptpb-H^jqKSofU7xo%KFWEA$0XROq0#LqU3y;YE$Z-g z4v5wAwwH*gG?}#A*4q9%L+)<8bL8IwG9Y(Ln!RXm`s&m)vLzP2JHT zIe;jQ5<$X=N~DaC8%mYyIC+ufV?rvRa&R;uR2Rb6)IoqG1H=ZjSe3k*X@KPUKTnbs zq+?tsG1JehjwN96>P~E6(!v>#aUX9yOHu9v`Xzc$Q}0#B>!TBOhRC{x$Zw+ z@nLn%jv5v*ulM@e%shS02@an~h(Qp2>i8u={8HkKtDx-U$Rw|nv|z4NC>mVy1uIb> zixvzif1+TlLD2UVL-loJECRy0>&mj$)94 zG|(}_i`V*B;oVz5imWP?hS$L#(W2JqcG(uJsma7>y0PyR=4q|Doin8vr?UBm{RDOs z+11-0R3-`{VDUy&DKpp{E(@k$2f@h+^HIgj;a}GfNZOZ31$k1Z*M19&6R00nu^P;G zI<($dm&Syo4#5HhbNIv4HSa};E3@UPL5P6W)u8vm0({9^Yw@P;>RLcSrBY|%ld}sG z9vviMdS(PdRO!5dXsN`G7uLf5QG!4sNLSD7)mA}PvHNWI%dXXy$+yyv?d>FMvR!eiVEjvrz72*=Ty~8pYafCKA*eK!n_K6Us!~T zcTeJ^50IPT+^J1xl;jmV5!I;+3JUuDB_Q!b+{VFr;A?5Q`KX`U1_dQWW$x9e3hgo4 zHjWG}$Ze{M6n5wND;}tu;0~Hm=?tpH1iK^S0|Bg79A{%AD~pZrqJ>CG!TYV-@)P{`rr$1+~mUItlhgknui8Bj^iT zEKTJcs!L&xiS+&)!y8Jyv{nZu zV?E%~$}AKFbqT_7Y8T^ptOV^&ulg5ktpUTtu}A*+Dcy0zhC-y_EjL6$@V~M5-a$=< z?YeJ}rqV@_E>)D?B@_|qARrwAC>UA@Erco{MGZv=5F~Vz-XkT1jvz?rCG_5V6A=&; z+*xbyJ?C3{fBVe(5@=P+xyze~k``*v}T-WbP4pK9tAy&t>!e<|jyQaaf zua8Yqzj@Q?rCbJtY{uGrlVw#ud639p|NmGtuw@9Q(%4;d&|>-ka3GW`nL_vBYoL74 z*M45QA>nV;P}#xKS<{WiS60;GqJuX$6wMNQi5AZpSNu*ztGf-X0ef~`y~5wAQrqh; z>0f~HnwW6DevEfZZvj4{NGR8-iA*%*WjXOm7rqpzDbUh&y>ZO~ODuck+cpd&YR!{V zs^<7VRUmRHA?bpVRr8%3@4$7O0li*XEx4@4=~oq~MxO_z?9cF;L`8zVi`S!rD{@!b zb41Zr7S0iw`r6b0y`JSGb{cwln5ru#BWT8-7&Hd;2vCk(m$~dKd*zSQF!HQ>p5uAv z^}9jR3~e!w*TSeh^pN?2Smnrw`eyfW=c$BWeRkU&*Pn|rrtFMrs%7Fn{WQNtAU(h0 zzd`RVX9NZt7;y>T=%^d4&Xg}c`7FfW*Bhonm2|MGB$mGSSuMH#RXLE&hEnA9=(p0F zHxs*|;rIpG!ap}GKq<)`p$_HotRkb&7AuMoyq)P%{)ik3b->8k{p;>HoIW1yymYSFvGpAJoTrCdR8_Oab`jGc-`q=Q zK5@v({66x#T<|QOae5)YAACnF)YI5+`^p32h1|zt2Yu1wmb*+hMlP<~oJwPNxZ%o0 z=OXZuqTHhBQIkF@0oJ&oSgcY|G{@`pGuw0oVqA}=ut%Rpmg#=GgBp#ehw_0^k5VWT z^XQalh6xls84zY_a_a_bN9w`X(W&4`I?o|P53XC1UAZr)qkTqEh8%W5%_^@m;H*tit&QVLlpp--#@(~Gg33a`AT^sg(lg9d zzhghp@$Kr2tDY~7qBp67e-QHZ&GmtzjN)IZS}i#m`p@<7j zx*7i2>W>#6V}ScXlG32l_eyv0)S;IJxKQ_5$ zgY)!Df`uz#`k40ji*DiC=zStZQnjMTj5Fphz^l0a4JW7H{>T_2MHU0~K`X^4b<-Qt z3dYpuH@5Ek7M0Ll(B`=N1Kt`aBzChobfW^h>3& z{n)ZOV2fl<%+iY9+rExLVj-(&={upHb)>&~r>177BZo(x%4MSquywC~73O6N;!vN| z>UT%ch$b8R22q%@yFm{JXqY_;J>p;V)0swqNz_-iH@d2SYopW+6P!?mp^%JL^*D;_ z1ZxtrWt3hCiKPb2RpL2Z@0CsVUY=}j4T2b?r9&Fbs{4Fv=R`*zA?*R>F$)3(PCs0x zIh97F{2AHR!lapZ;cTQYoo|rVa=atp)wnurX3d;K%sLxeZ)&y1oyYapma7TO)uL}o40YosHaGfSgS zoDpr+m5;XxDk&yJ;h|Z>SEZ5f&%jpQt4(>OdEXZKRkN0K#EF{l+8(n|f&dgiu_g(yGc{i5wgqF`aly%@)=}a znfdqkpZ907^erA4Z7%LkHaSm$*DnfNUd5EI8o9ZdU(_%3@MQM!_s?~b#lfffNC)e- zAv6j$Y%ABj&eh1Rs_T00iilO@lrS;R%mljXOXtGZKd6%gE+|HeaHx4r)Mx`BU4Pyy zycSm$iWNQ~*6;;=S{zNTxL(Cor>wDCkLI6%+NQ*2$_k_$XEHga2hjy`_Sfm!Ca6eYw2j48wzF6n zri$|X;wT$VC5-QbTUxX`PPOTE^*lKjkD*$3pxjv?+?w^}XZg7LP7BH1&a0NWA465h z^@zHbiOB&0A48@Ty`-7$R8=yPoVTzx_Efb&19%xJzpS0hzW>cK<-!sFnx`{Cwo0*S zM`M~B|*!oA(A2LzsnT<&khIP z{|Cz2EPyxy`YlkqB7pVO=Q#(!?lpj3o-G!AY1F&I}gpw5++Cr?`IHkOI}xwp1uo_ z7`MAQ>A=^WVSfR|vUWQmw_mUs@FpGF5knW};ArpI&FDx&s*i6+`+OYXhu&u>-MpB^ zolEu?+HJoTJGV8QYzj4e~_`wP+-TC2TAEciF$!eR>!c+mKn3kG0(5;PwmX1}4 z2wVf2&oIj$v7E`yy(V``4s*w9&YO7JBD<$_BVKLW+dDD|f8wZZh&1|R-oHapx7Mn8 z8KBbh48l1rzOuNJS)~Az?yvi-wGboc`rEm%$yN>lI_qPBZv484|` zmG-^?g@qlyEL$GApcG`0VWJ1js3Qzd5W3_BWiDz_YHIp=YHrtb@+tlC&j7(CT(7S} z^228^bJiMEyziwL0OuUS@sMf}@Ia704n{-y%Ke z5J?vu!(8i|=_Ze1^Tt`#9OZkHe@XvxA`RxKw7R_wgg%S&Rn|)A|gIxrf=6%^TTL^0%MP8 zJYP#$SQI*vmwZMhraP#JS&?RM(*=F(Ogbrc{Ls5{{0x8Br{LrHlb?|7{eW6o=SLi_ z>szZMA=ZOUAr}d6+DCLZ!8?Nm_A0ry5vAP5`?3eg9SPZ)ihlvq@dJMQJb$i>4YdMQ z9)=3=-OmMN^>b$j7IeKntvkmwD^;4 z(f0BqZbp8No4N60m08gvZsrE7Eo%Y|ivsSI&g1=v+y^Rx;-5WCeSJOIUW!E*m9pL+ znw%;r%qcE{tXfWTh4|B}oW%&Q#8kx2vO|;woy8@?7d6l5I33L(~yO|>_E(D?raaGPgsd#sJvmEyks5I{>gcqv7K4X*{9hDmABEg0bY z7pKb^wriYK{t&U^WxB1KFK)l0C?xK5&s-yX9Ukrx@&a(f3P1c%0sXdpN;EU7{$pwU z|8gpMv7`*j`%0xNcrpWh_ND7k<`!?f_rlq)`HlY?|JV8W|HOPKh@~E+sz0m$IAHoe zqSGp8twRf^n>bER1jSrNsUP3kc2E(BBaP-idmwF-KOil2KQPyM4={X?N{Zg-eb5BIIN@fxFk8{gEV;(-SPIVpJ&H?Rr zuhp_XamU|trTXRw>}N9R3XRZu_(SMQw7ju0c0&2rX?S&LF;mG;1XyfrWMLzr#qB8D z_~DWH+>h@wf&MgC@dWan)VOgYk4FfrD-^R|JYoHc)|Y(^v;~xR zpO1=LP`5@8f4nz}vmj>rTH9($k*+6v@oxesU%YkqFf?n19m1BFYs+F{o3mYRZd|av zf)&MrZ?v0Xi&f2PyLTGO;*#W0#y!Ut)3Sau)QEiC1t9(;mk4m_(&oJ=e-xoX~A z{UxsVWyx6}r%PFyA~A7X=`~q-ca1JVAVy9ryx5TcTl<@40L3E`r3n_xdx<$+KwJ7D ztD&Um3xw8>i{ulrctrmFU@X{tq7DF6*zCm{wau^HQg%pD|NQo2bWLDY&c&&U0bY}3+Zcd6VJ2Fm`a@$$bGB#d}3+Bl>R(x zF%nEeId^SntOpiK8v|M(BBN@4E$d-3ai<-7$nL#^j%PoEn5g)YJ8l_VVXH%mvWL8u z53FvYb|z&MtVlRA*rWbr=Fz1K(yYr8$w~Ad{}crL{-9)4+y(UQA-fE`-nseqNa{08 ziCVtAWC-k=LidHcxOQyw1kL#8S>=_b+1FF;&?g&BdrMauw(?Qz7f%~5I~7THH%hy* zr6l|E$b2Ns@N)ff8vPTIVeR-@FC2D;Jr}+JIln2{yvpXg z`+`a2l(@{wV?q|wjO*Dl!V;VK?p`ZNJo=cK{)u+`6YZaw$~(VL2I{PeMJt&P2C06! z!t3D&BrkWMxR~n&qUB=6U5Tt-9U+?t>4U>ROf$<|f@ye`w9jxi$r1VQB{{TL_px`w zZ?0q~4hGEkkKTnK3jRDg;DP_XH@V2&WMcHZ1jw{H#K8^txg zOBH|bDY?SEnTsO%*XWq6+4|JcaG9+7!=X?x{3rV62qeShv$1uxEf;9Fyq}B$i=-!A zQ0?K2TmIc=d6`KHjh?I%0H?f01jy+qaQzf96i!d&Z1jry%blhZWTQi+$&(t-Ktv%R08cq0rr zZ|&a{l;7_h*Yk=%MtltPwqrEK`Dsp$>oD5<>E!w~XQ0M48WDi4kKmeMD()i8&WOR? zQH2?fo{T-Vw#KIr_MR+r^;eDoKz_-2qaSnqUY^XpuTFmhL&_eZobymRYegtfqdQ%h zI7xpZfikK`;js&p5+HwzP69JH3NPa2?I5b#|Jkzf2t&)tQT^mZi?Ukp2!UmNjM#=h~XbE(v7d3I%=wZC3S8M`E;RPgrt2^~5Y z$RCj8H@z@CeCEj^&1j>RIT!md(aYmh-&(Pu=&{Doj+nKEj$KQ1;nvAm?Do^ir(FAV zX`Ob_{49jYIvtnM4kSgv+sb*&Ng;`7SN^w0k+_12L}bvSi7tOvbC()b77Go_(q61$ zTpTb7UXi)v2szU#&*E$6fke3GQ@eTC?&Z|KOFq}))mv1SopZvVx-%FWT> zASC_}onlCIU9V@CVr6qRCBsh`WT^YN3d31;5J=H60|VM31N*E&#QP^RuDutpHl=bm zEjy^*J$9GokC5on95CoEN;2^Uc1ElWQ>pf>d(G@(eC~Js!NyGS$|0uePj(75?}?Y%!{6lEdF^yh0GBrT zu~-)uQ@43DNb{@%YSt?y|CR+7c+6$ZFV_I9dUy8PdgBUO7`T++>!qsIZu~v)Jx0&^)9j$XY z@Y1y+D^F^yG1p06Hd2p-^nC;4n?BO8eB7CDGQTfL_bF}Mlk76tH!yp9#EA$L;g5$0YVeimF>aZBu_;J`)N^&jR*wSOz7!z z6+tB$-qz*;30nRsvS+#iyq(q;3sYfeG81vX*Nenj_F8;{*ib7 z3vh4y!!%~CanGk8k{-H&msPn)*ZO9^k-g3E7Z5X@9^KS0g%|WZLR`5D+7>^+QYGVd z-QY(>X2Na2v(8Pjdh=v_ zb~2G5*Xwr=WSElk9LXP3#FPq#GRdre+4f^9W=+K~TiK$AbSD#$_47@C0Rh)y>p=Od z6yb-6mnytf1XauS3x(;-#XPwbVno!J0qa&)&f~G$sL(qacQZIYMi{Hhu|eIQ=~Pr3 zTyc=ak5P`b$ehH%B+aqd%2NG&OUixS?-kj$7r9^UMJUY=&%Uj-5v+HKY z_ZQ%UDiF3q3E_kHe7sld%18f5ta|0E> z*N@f(UXSW{6fIbQT&L(L(8@@%D<1g!tnU7c-kGy3;4M>hY|7pFcdg6g-TU&K?=0VE zYZ$i%7Uf6GGiF&C`^!jb&!Hb8N}f}SeGLN2`tE zWQ{w}5!z%#QR*GVBlAtC3Iph@sB{sXU(w+P%J?{S$g%;?_fzt_lEj?1An>jEx)93@ zl#@nTm_3h3&PAipD~#If3j@})KC88pKxin}5(*#(JXX(bEWyzsJnev$I) zo!9>O#y`56E1wbQdB)2d^Uo?bUf%0V=al=3mm1o6Z`ST&4^NnQsY5ifV{!vG(ohY@ zTesqlf3{T6k`y$wdswAnF?{xfW)LuzzyyPd`(jNx!J?Lf&B@_cnkhZ z+flWJ)7me>=6Owl=kjfvsB6tdbUc+a+x=N=i0fp?=pi@J`3Uf99LGaap1F`e$R|`x z%^G@)+;HAPI7gS11@_he&$}hA1~%3>t2JhwTWiHuCLnh#CVC8aA#cl=xz+DgTkx)p zk|De;0ie7jJf?A5Bc}cZPi`aL!&la3JZZGY$e=rqmT~Lcopz8#(^8rTtdsajK66Ew zc35iP>V<|Vc}QdHd%tbSF3YeU*A4K@2CyHl1I1HvFw4_3rRxXwAgB5X zBNOYqCNqUHzok>q4yb!ILD64$ZUevvvnQF;^5k9-QSWiDU}hf2`lN{Fw-UYXe&beW z>}M^XBxfh?)TvSm0$|;DUkyAk{SQ@VUdnpM>6ahLyvP?RbTfYez0b5O4sLtR-7m~9 zg=Ude5Ke0k?7a^9wB?msRwL@wnTT@DCTgj}z zpntmbX<^|!*4&fo1wS^))TX}` zAz2p%IZ<_L;Q837K9J?(VcL&>i1}kYpSVbGt|;2_zg%Etf8)YlnAL>0f1`=ylZTBa zCZVK)#&-mIo+>p-JE1b4?D_z%zg6stnD(JSAPy<5*))^zQA+_LUwLhMhofTt6WdnT zoePSJJp>~jXu+pA&nt}2w}u?Vlb_@+gA0P|Nkz!R;*0G>zuiua-t$gVrf}=@mOU+f zUr{wc87FF;)|vSipb_72AwA0`66$}7FI2_LoVl=zk59A~w!;#YFZu^PIgoV)fo^wcAR#wS9lk1EuJcO7gt zp9p54{l1xYtn`)P>`xm$y3GhRLZ*iOrAM|BmVQv8_FqhoItbk_7V=9!qDr%VP6`1X zCvmD!hkzO|72cH~vBZ`Xc1I??7eDGMYo~vS#2QuKpXPW9<+G!Kf+PT(;ZPdomVp|! zfG&$z<9u~n>wo8{{`(7kSYVhDy>*|Oo&+x_;5nVd#x=SXX13+3AeHBnH!4i+@n_Ri zpyjhL+-=pOyIQBe>W3}nU2Hoxgt;gq<;}9vnoNcVI0ep+2Ulbs;j-d~Wt~$2*&Ol} z4fOEd_Xaa2rZUET&J}Nu#T`DZ1w3E=Ztl(g+dsQ@`o1%biV(U0g;Hz_c2{8<9kEXA z&GOC97hSYIJS7}h6@7Sk6nAi!?CSe;k;1*^$A%-NZVvIE1G+xO?3B(_N1$p8YJG~ZAEwxzjHn-A4W4|#P1^NOBNF%9M9dulZ}_yW8_Wh8mH_DVy1wm> zs{Z%u@n0#4>G!x}iMdMfLqx19Pk)$jDS?#ScRv{lA5UhiBBZ>It@_qp4xm(215GwB zIn*&#XV|~KT5D`O2baxiADGGAbd4N)NEiHcY$wIlLyym%b*Eua)Fa>vV%w_fSQTex ztyeRS{a|r(24-j}v=wLKFj}ORt{w}gWg{V(u|=TfV#}Z^d3vG@j*fbz8?DOmO#TY4 zX)gIC@HHu=`o|lwcbdXh!`P&J-Vu%ph0LG7<1ah$8#6YagB~bfBQn0UsK-as3g#;{ z*{I?d0_+^JsbnjU-IZsZU1#h3wnUQ;laJ&SSl`2MfW4MZwO1w`zC?NP0b=3$;ZsvM zwaK8;>77eQFBI1E`Ee7pLAw0R)oV3P9yll6eXnD0e$ff%he6c2Y_?eR39lon8y|l0 zMa#$*6h6^Yg%IN?de#SYQZp>0AuAX~i-O;xOs$8n@^G!$xkB}xX0jC7n8!<9QmJDO zt+pNzfk^Utf`JWnlRe|!Z)lZ|AN%Eu^@(l!=d!%?rEOLtor12w7mUdLR2sj8w)Sr` z?C3Z}<>$R~o)*^nnxpd&p{@PoYq*;rp*tp&rVlq3&J-+A>?!mk`L_brs6`Bh_BeNX zLYklFw1Qkc>U5qanVEqK68D^`)jJ59sa+J5_16s0D{}&Rxw*U>Q~v~I6CwXd^|!%a zfRXY2|M|>*^M3!}YPBvIYrT8oSg+Ag;i$~f!X|(AG$7Y4p`AaR&|LMSr6A7_G+JEy z$$G|5+)@0YqUo%mQ+A{NrvgVaqKhmoS6aVV zTIN(14-@UZ8BPM_yrbnPos;}I79ZKF%3oEVl*L|C_R}7*QTPq^Y1*2za9q`~$^Udoj6-TN%#wW%2%exxq`Wlp-jL z?v9QY4CKr?o=LD^J_l3jcG7|?St}@SuqoN!D?`%!F6rojXY&&LBlWHi%V*ihSHwG1 zj9Q(V54e^1cxK1Mut7Lk1q%9OWfHV0SvlLS-LnTeu&2c(^F{&!jsj}JE~TlYamwm} z!JewAJ8zW0Wi8;h@v$(k z@gi;hRZe5}R?(N=Y8Xx2Wt~Qzm*stK);E~BpG8KIeg8rGcux7miq2~rn@z@UY7)G& ziP!|kw<>qBAzMt4mT%1z6nem9`V*$ZN$`Sv3QqjSAxayzoO3X-GUqBLXb89+WJpUe zcTbKTnW;d}=WLza(ts7!x4N7$Y>ktvd%Syhr2IpZ0%h}c-<@dP+R>9ebn) zK%yg_r|7#BUHgP{pMt)S83f#sXta@y18@qOR5A^;zIQ3b4QB5K7GVj)Ce|B;L}gTo zU@}36-#`rJGCwTRYRnoKdjTQ zW>l|n5t{SUs&W{IsYp&an{}_A)RGg7dfJu7PwNE?gxW~=-*Fv$f}Hft9^cmO(R0gg zEpqZ4tLdQA!=Up_he>&gV|$5*AjisU^6}+-b?FCs+(=8T`7RTa+`WMUoJ=mgU^N zaz;_xKnr;I3~yO6XCf<_9R6gwl0grU0TbGmFMP^Ln~H8j2OyzswKbIJheYE zjg7rK!k9u?!@2I7Xa(K#XLXvMQMgf}(HgTzuB`8na4=0$ELhH$kbO&&BJiYIlL8(~ z=(k3X&fIrzGQ#;4LmzOL!&iL@7=Ht&Aj0Dy;%A7qxm6{o@%O z;=j!-$iJR;zct+}imgr$FUSkvfkq1q0{fA>4B-eQ74&Ig|I4@PR{zi_`=9;CL@n{Y z$o;Yr^p!Sb>q57_h2Q-Im%IAHT3>7Dn7%Z#r(o#aV4%yn=-2_j3dghqI9>3$wnzb22;<)Yc0}m zezZP#Wy&!7k@=w!TH0?_8hhN+?FZ|iqSDxE%oUCQ2;TYp`!WS(p_~}Q-CLj5ydWFl z{)(1MN+)(xjFdy>B>MfI)DpMfR#vq#lUX0*ohq=&=;>0Kd4aSxh3mD_<^3%U3Qr@G z8fZC>E)0<6dyX50=w)U02cjpkcfSux_MQ_LVWIhC%vc5#U zT^G3s%p^H3FT_ayx?lRlj{Wc-f>ez<+K(D|a=d#?1P@*zFI`%uV|ApKX_L zD!zX{5467}ArofXuUONBj*X ziqvRjU-_lY4I19Q;W#s2j~;VFGq17+>w(?^Tw`zDF4|SINsnVSY;T9|{PA5cmYWMF zTL;_zQyGu?$6sud)3h8>ZhcD5Exn&QQ4ItXQ?ioPM@ac3=GO`OOz#NCkw4V>T!Pah zb93-H8Xj&;u9D4T^KuN}V|z@>g7)~Qw(CarMSLhuWQg2Hj8u;fIS}~nGvYxs4L`#hR!%?c z@z(`8LuWBL>%n33$$fHL0#&l+MRvN~zKs6ZaZXwgLgExj@`c;$pl*hkT(__8QTO}+ zi=5sTViy_n852WV_@MEZ^A!8V&>^%==9<*gzcDjOmqH!Vh&hKNo`>+j#icCnW|>++VwM~vSuY_M^f)=d>ES*^$( z5~=P}1}0*}WWLRtH>C1s9^)IV-3u_et$zVE{l!>NSt>sbDlqe5dwMMQ@YZAla%qKDR<=W_ zUWB4=w!OyINlsBome$uyQ9Njuc-G^FQ}}KD^!_#<`kv+%5?SRTyX|JzFhv#~ zM#3LEA!=Ib{&sAlPoPzv58Kl!3gvScOn=PE-sS;|dV#0i2=MRqJ3a3*d!F4gw7lIX zDmD%Rhw%B2-%==LHoT5NLG-4+uZ)gE+IiyTmApnfA{rbo2wU589x}1p^f!w$_;Zjx zAidgcKU#?!gYtG~Vj)$2y7)2c^&HgnlP%FP*+6%`Y(e;Hu^qfE$ZJozEi+49W-a)` zOvQk5l2gfpvQ&su9bhIJd$8vAQj`)V(;tQ6GPDGCkaARuO*IDQbwPtvAZW>p)OhnV z{aR*)QlKjY^C3y=HbtQ-NBEF~okM-4FG8^@d(f4|5AR&K&7RT1kGQ@lJTvLA?NOnT zmr=>G+My&7NN!EyA1JC}7s%SU)%Q8`> zf$8^C#g1PK(T~ul`i4dqqHbuvX1&{^@(k#zK|UnDq4tD3G}?aV}q zLEV5uv4di~^_Q<21;}?MVQIs&2c~AmwT*q;S@B*Tj|WNCJ6{WJ7MT1TjQ;Yz;NYw& z3;aBG)jT_3h`PdL2h z0j^C4NzBJ%jSpG;nmvy{EBLI|WQRv*Y|5eCPd|7*Ga@9+Lq?EILC z(p5d(Gr2$?w1oB_nS?IJI0J6`Jm3nf9ix=KB1WAUZOss*j)A}}4R2A9aQjoocXF37 zHB{u&64$C>3TZi`Z@Bv($3`6HO5)>RMxR05d>KYtmo=x?{Lq?CE^uV-97$$UF~dm& zQ_icHIdj6TB_TTj42}Ob<+bOQBxfnt7Rwn1^hFXohqs>-?W;0(IH*y8yH@-phe9_K zt;Z$^#(iXFvJz?{2cwMq2{PRQ)G}PoQR@r0M|3zU#G?0u)ZXhry1V&_|8V`$_lSJc zXg;Y%?$b2T@TRoVV;~@L&MWj<@wSBL!=SCY^s`sKvAd&X28usVs^-6u6<3|qW%yG6 zXt%JqZK8FfShD^k)=nNZGB8E$_qd1U>>W(aTIU4=8c}#N^$j+qgFApSTS_q?{u>B2 zc|EtZBmzZgXd(0LNxv(~0)cf{a>(ZBtVg>_(~Wu+EZ4xl)ps!L|t#}AWHu&9j_qanwW@`q7Q z=m3IxKaI604JGTMx?m^AW zO+HE$zAapmF;|LN)8phz3GItzx+z3@e!n zqR=#SdXn3SLq+h2`aZoqatA_}{H?7N<_pmQ?l&Ltl8}!qc-<9VkmZ!kNPLC z;~7)v186Bf!Yp2D_hX`z3(c{>{vmqW$Nc^rciRfc+(jXj+l;?5OOwCo6OoOLPuc7t zK1BhNEaYt|{s7Q2zP6~obgd*p^x)JbjTr8zZ%C>pe-iJt(-dES#+}Sm5z>oT%qyB0 zH9nNi3l+91<2Xvfr~WZ3cr-HY%7@a%UYN)F1i$^$kNbj#*TQU0nH@SF%Iu&MW$B!-ohm25Ln7d1_0dGUYv z(8PGI*mY`>U_NSqZ|<7Z5VoOe8v{uME;)0~8Ryp$gagYUD+M8Hg^+hh5iw8ea?T=c z(r7;nhLYp^Mum&`MAO>}B%<-g!Y1&O7|>1Egl;`=fB&votRTRTzPC)vjtnXoEJSNl9t=NJ%45g%|~h9a3}9 zRvL@Nldb{2pKE+VAe9CwAFWiK>RrlC)h1R46eL#b(W6+|_@h4qlriwf+>w$~9JOSd zI6gxI`6yypK&32pmIreGeh8M-X(|N!RvtszR_MGjdZHNJ>s$G_5rvqCP)Eg2_HoG7 z&W9|N(SLNmwbwq=G16z>7A6&p(MkQay`BIJ9~fRP$W%-Jz8a5uRTPtciG_h2(Tq>G z9Ub%&fTJDMfqs<}DcVP!2lL%rB%tnCnHBjcr?*DYSrTy(7Ffw4fU783!i@vAtY6tD z?wqBIclG9njin2n^S9sSg=TKPpskZ0YCbF1@EcdvtNGmIz*`Y4M?Sl+T5z#shGm9bp+cHO2r*LN)h_ zHsDTu7=`xgFNg1-<=Ir;>}_nb)Blwvr*> zTe|2qWcVq+bTIQU2YOs&o(--sshTf7OSbxyCxK(sF?i{4FRNU#PCF`$3V`oXuhlM63KVfHU0F(1NEUOy*?EC3 z+$&f2^I&~CIv?WWFEVNBj~zBM435{~HdH6HD&_7EqHDx;<{ydy)owZPDSGru?C#0C*A5|g5yfReeex*Lsy zvB~&yoX2uy@2@_I(}yBp(7C^}QJ>9n3Rml^C!&YjS(w)^^zQZUD>Dh0S}3@{$VDXO zsIQ&M)DBQXRqt6eapu?1kk5T5!epKeb}2;W;1p&oIWchNx}W%Z5_X$qo_VxaP&D+h z7eBqBwT6F&4Y42MuA=Kxs}FW8E=t4{1V)HnYc+3Jl2|1!-#Au$)<4Pnn&Z90>lj_o zs8M}o<>xy&xjLj9$#Jo_wm}=5>Jp6-wmc*RY*HpeORj;RrdVLDgt4)kGXL#b12_B6 zw^F&bsM6uBe!Dykblfb9VNzf=n~m~&eX5=j1K8MiV@|kIl*YUL>S*umo3?F7%2q7x|E~xv8o>b|FkERP)s*h=LR- z<&GXZ(Nmn?I7@I%x8_u<89Ax!769vEjrNuIK186tY(>;s32dB*YwNX)$g>*0;lGP!SyK}dxx^O4m zw1Zwt+Da2MCF$}T(MM0adKhOw8}bhFTx1M0w=)lTnI%hb(ykgjmE%FFTr%m36_}yruIj7`^vZcsDeetu; z@Bw|_yf(aadP?LND-nS}v|#SuXdtN5+PS{56_Ag^pr(b6wVu#R&TW2-&US6$1&?6_P%MYy6Hz>fh?u z$s6}QW?Y3Xj+Hf96A60kZ*PrW>xcAokb>oxBhhtF?eh_kdtL8pKcLwbO`|EdOfyw(97Eze2^jTUWEI`By%a`d@%3n78@K3&+U&?V`-x>v`Vk1zP9{k zB+)sPsE-zlnMVXVQ9IS0Gw1{7?Fu~^2n->p{WLlaoU zgfP+&PH0G>jf>P5WNwuBVLM5ZfAZWQ;nJ?TzAh)XrbNoUh!$}(U|S3m_q(`c+d1L^ zb-aUAWY`g-quU|GOAN*kwzNcx5fq()?kA4B!%NaZlRl@F+7}kYs3Pp+t>Dh(J^7A2 zL6dMnB@1o!EIoasm1*}Zyijibn~bzs?XZvb8Fo-%i)01RN7_*zG1pMvEqK$i81s^C z*LGrOCN)EpuQ0q)V+{SOzkU;`b!~}5KAHj~`EE2(Id|Wi^X(^8l8gIcIpS5|TCq5F zagL)TJd13$ZIJCfn|g4R%lHq?Cqt^T>?Kh0mFoMD9LFwHDQt{3c$`)NOle^$C$+Dn zP3x?L35y2KO|uXq5>)-=&hM2Wmt4t9C0mLxZVVm9WC$*GxOj!cHI+5yb#i%}gj z9SdPL{9Gwth*G+GY8eDF*$wci58<7_`eqUuXCAPQ$j^TGsbE2PVIR`=v7>!rjM7H7k8%2lB~(r#iF%d?YvN7>B0hfQgB!9kgy(clg1C~!+j}Pk+?P+V{&-BLNoqg!dhHY0D`z&Y$ik*D=C+{d|q9oYV zQN3Ce>lhCy(4JdyMhsln+RWi~IXd^|=D3=Mx_Ux;9*lmW+U591O;afSXnB3aFo2|C zzrb-M`A$q9IE%%RU$X8tLHk?)obN?VSnj~|qc}!Ubbuw?m__J=+Cm%Ax>P>}SC_eI zp%Q_G&aE);2E$3m9D#rAOncsv?2dy27R4+TF%GLUAMU+?s6Q!H;1N*t?d_6c1v_8_ z;%EWAnng19RdsLLd$+nX1}eCgUGkl}En?nVmkPfx<0*uf*ebQ9IZ9?(iV=PGD=<88 z1=sYBKOU>E+2N`+OfLhMWD*qvtvN6;H!ahsd`9UvDV5(9DzAM4fHnb>^c?#d4xApP zDd3W2Lc zDq-j14+joH!xyyqHMq`OhQ2HI{MY!u&c}bvhyVXx52ih&NPzzWK}Cj%`275r-EfRJ zs=CjuIbwry{h~>2Zh$Lk>0s@YJ3Qw9(S=eHqrDFCF@(-=fb?Sw7261;lm}tzF=l0Hpi!b}IKZ z_*feyW?|t(xp3adgi}L#&y@eXpS46&#|(>&avWypC0 znhKd_RCmM-<`l8C_YA$({r&4w8lj*7f<=B0`u$t_?*8#+yCZNNeef5sr4;S*+7dN!oUM z1jB7zj@L8ZZdon6S{n3tE7e$Dy(O<9(AFqHGSZ#czQ-3eBY`p-Z^sAEyIS_i%Tm+Z zlEK~S5!KThY0SlJ?n~;Av~&H>R6-T#Bwl-G!~!9)^lRNrm)YtS0YL^Wp{xjDFBfig zEmwpMFJ8D+y4<0fOh2dY3zV@zU#8eDczT^ zx+H5{*rrws%ggFLf2sQoZn5}1I2K0aIk~dZ!IM<)ynN6booM%kLl=?CZXn}7+YCRh znYL5Hoi+R4bP|t;*ta;nx#7l56+21!ez}jl_HL(Za&`ShMo0!1rV8lFFor{dk(`3R zoC$6E9=loWQ?Jyy9)3lS&E-9mDJ3E6k%Qh5>Gb{9c?pYLUO5;Oe1wNPq2LZqX`qtc zGgoh+r$_@JM?tk?N^Tw~PY8h;tNNsMjGNi6Y&{Zz! zcNH2#R@~Gipcgn1nMbob3+*9xOx2K_J`2zkm`^Wqz6;Gsj_9dCYL-8Id@RfUFbcdD zn|!aAL~935%R9)^1IT7s^^d@>^L!NJDy%g1<;z?fNG1k8Jk{jj{fK7(lSaZ?5KdTq ztXWC<9bT0aehe0L4vD>)Z?}Me!A0FP5Lt1qtwRs!43U7|jTkB3eG)x=mZlcpqP0+J z?Gjb$cBi_>ZgIdECFBChi<5bl&+K1to zd(n2{ypE?kBK?L;W7Hp2y}k0%O0?dXhG>U@j>7?10zvc*)@wjfWy(~u{=wuYZLfFE z3NT{R_{R^wP-HExHOJuOO1eOL!Q?J_y4>vSHD(V^`NWFUnxST=M`qgU8U$}5mCSrL zjZOOm?ljMmis`sF{^7*1qO$AKl;Mx(ERz#WryTDHd-u*}mAV8Vk)Zny=OEwSY$5Dg zPZ4sKTKKJ-Kz0!5QeWcrlxh*LLQkf%6kqq=2&|wrkZd7^P-9Ej!JPXKa&A9W(3eyN zZG?y8bb_v)jsp(=F#I24+@ep z!ND7*EhM=ObK%DC_-2a*?mPR5m&{Kq>gr8LxTHSM?EbBBAw)T8I;`zWXzCM6#qWn3 znICXEIwbZaw-v!2Zac)oFKc$m#?+NwQFRaE~16HrRmf!KZLu-)6}k#VxKZ$tXy z6B_h*lfGzr7oOuk)v?EguvSl9Ig`KRbb1%%Q332&a*;;nuvDQg{&;d& zJxkpW1!P+dc1KcyhFh>&CHd?NzK%+H*z-!3TwnR9lf+-0zO#%kn-){L1-GgVk@?yZVuYMX=@`! zqqjcYR2>awr|gGyQD}?s5Qv2fD!>d2FFScFMH6ikZX+XBi$AsS!hc#Zxk%dK zSSyew>aZ*3a>MxbMKUe*eDt5)!DrTBoAQ&grD>&cI zQhAU48Q9-WwrgGja4SEoLPDJ23tbNpcL2S-M zNZom4ysv+kf0`e$%<=gU1y_WaI< z(<#}T-#+OST}vX@rxNt#Zn{|;TAwbKUM#-56PNX_->Enu%w&Kf4M43%smE!6Tf=Eb z*Lq3jexAKz#n9t*)nwWA#>6A_Ima?r!;`zf$5wt*wG)G!bTu{Q1x+(Fxd5KymU;B0 zQylcn_MEj`9k!w`c+TP{-_n`_3a<_ ziNWmgqr`A%wn1)*8cxUH-|(04f4gzJFD6MjjxALb#K?S)sj|Ry6uMV$2H%4ztFM^s z5o(JtIwvb{Q^Q~4Eb0mGY(sgjH2uhfC3;In%@iZ%6v&td^o{$UV|HX^dUfmQzxW}q z`<=lShrx;?_QyV+7Lu*TSGVl7@67~v1@c@Ddm*hi( zT#_J+*OnloyKcpVP*siON+u9{m)skUJO{nRrhZ3!x7>IH}pt2o5Na05GV89hwcs&xQZ6$WfYp6;b^LVAYQMaVBemb z-ORQmi46hm?(sj-{;FrkUC1zV;Getg@;uQclp^+hhGLy^In;QeoRGeQtc**YzPj1h zYA0Ce1%?wG$xfRJs@Dp-N&P73_A)O?I`&`jH5DhJmAO${9)-9KdkYI8)6s4DL5?}Q z)fqMAL!hn_?KKUWBL0!BqE8A$(ZlQnLWNZv#HAv5KCVP#u}51V_uT$IL;WdvxOleT z>(}eO&rYD1RBj?tSRA-Il0mBKF-ZY zaXW%g^WqX#O;|Rf*^wwzY)&)R`8G6f*GIJre@cyR+%RuE_4nn{f*f#HroV}b3KA-C zw!a-ZL+2>#k#crxR6+guH4XpdESqtqI-~6wrJUz5MRs^ehB`=+k)2Y#yT4;MQog?n zq+Q{UEfJ8C8o7010Uf*iZ$(0lKoKRJszF@|JFT&Mni0f8TRrfTog&?x{HD{;jUgM)o% zA192sI0Ok>DbH_=j}A+swIag@fW4KkGQKEkd0yal#($w|mzYr=E)V_&h%S3+uQ63| zx9+wZVc7ZU@ui5d@YWvxS6w3`BO5yWitiZ3xC$JiR1G$sX-b+>c{9wfXVcMm?o1^@ zk_EMp)hR+SpU&;cJ@V(83DVQecq0obhF#|{O%8vE{g)-_Ro`P}e~*{W7e!NeYu=2h z+Ig33e{GsQ{-Tg9!P8nz7rCmV$>z)r4)}f|Fmp$@xhLDIKI55xQKP3{A&tCW0Ah++ zEc;@ROK->h`k`}2qhp@=P}Elf2f+Wcasyji?VFi5q6*gO9)%5W5c`6jYYCnsqdQvCPIfajwCdIGA)8D} zs#TOa1N5UUPNM$7A+%?v6SKGVB_`r*6Sp8vi3y&bD{O5=XZf+DDy$|iQxTQ8_{)6Q z63;N~L}oURP>`BxfrfC2-8U|BppTLHz_gu4g>5ZMEb`+6C=C1VLw07{IPLRm$2E?! z-W3qi#Z*E+7v{g2EL1W-5qix;wmz6fN2w+5N|$0BRUZHoBKPw5pn39Gde9(n)%&P| zt_#T3p*+HiJVL2&el-Wb6zcssQ~dwY!n*ueAsM#2S&~)TuIR*nN8n&5yWz!DvX04mH7A}ax zM|r#%R!7({FO%>4-lum*I3bZLSfK4^=c#vY7x6xK@NMOB!*p@V%c6VxLbMoMqLk;4 zKKbsML2E&0L;A(9Q>Dg4)}q?6?a8Z(xCPIm-H*Ffm~RIM`!FNuaolWv;z(3^&ny^l zk){~;_}JNu;HmBx-wcUVB`)h`qDRSl;am2YCo-^ zc&&8vplz<@Z3WSP#&7Xh#ZSUQwcNH2;ozUS>c-iNWMj`=IkATJthkS};21Ffy>-*(N~Wr{A=csy#3IwSpUz_~!=eUw;q!d%}~oO~FqHTGIou zpcvQwnt;_ghMyi$$@b!sC2@oraEF@x~SepAmLd}VM0bjsyScvCIk7=ejc zr$kcsHNI>6JEcaO%k9O~og&ZbHycjQPaM0Vvip0*-|5E>KT~x75i})~Js-DT(qx*{~bO54_%;OeTP9FgF-T0RD^Arw3 zu3-^@(008Ij919~jNXw1#cJbfCjHkilgXQp-WVxLrpN!7laP;SpYg~k$i?HtpL{AT zT*kyj4=yd}C0>Oks4*CG&m~#r5dA_7@67NaqRv^SSk6zI#XN!=`nWiaq}GOC_dCuA zEYQsJCxDr3?Xxt0B{Ip14p%_^rhkO)r;D{rxNo#nb@XBOOT-*^lfm6{c~a?$oPOLJ zzQApK(kjI0NFn<`YQ}R4Qy<{*$DBu6sDVAJmgpk4etLl6?$FyxNGuA4u49@ZOKs=( z7VVRIwCrYa1j(`qj#!mr zyT@|+e1#uhdfp*Rj-ZwdsV)AqJhx>65x-P&EMte*SM<+-JJx;L|3(lKv$0Y86a(zo zk*P?nCo4}L-6})dC$vCbAGi0_vc)YVj^XU28us||3-WR4sPSU!OGQF{yONdwwmr|$ zsUbacd#!t`b0|00*maDN4fwBBJZ!A&R&!tJ%KKqa-eq0-5_z{t{DDBTRml>&+=;BEr}{@R)J^nj+t2SNwR$6I}F)E%R)W|hv;8b zw^gM{ELqN4@9pp9DBXl}DWWCJt3STH{?6mT*}2h|Dp>@;q{iXlX3NHObANy6JXAq#QhMS+ zyRcqg^|+C6VRTC8FfE5aSyyBI(yUEA!jz=$Da8_U>UVxLc;l4UyxM`r{lk^=qTmBTiY#{oz;ls6Y+6vgOAC>4P4SvR8GdCJK_CETi4V zS*wB3yf`Gi3z8~nEh%tE5&lkEpDap%Hod;@9o#<`QlkvQp;vI_EAWQ?-4%5Z^I(4i zzs+mGrwI(Uc89ndBvG<2df584n6>VaVYN1WOGrU+@;JMuv2gN{lf0Xx3>8(DSC`#% zT?93X~i)>!?zEyy1(0Ama{v5 znUReh2A(F`q7pWuEV?J5DQ4~I9`1rgA@NzvdDpQ*^RWWSDviIMn4O-9Sr2l(`eHFQ z@Zd4ac^Ssj*;|Uy@WVO`H{BxT?ypI%AA@y)O+1uhvVxArfw>>f*-!eJE-55pnUJS! zW!tWwCI4*e16+UO)r9r{}& zJ@m2l&E})LrU^@^Yh1?fo4~Zmdt%0EQLI0ey1jrjWg5sifvn?FJn%{gVpo53eSG6t zTvpu!Epje#7pJY{eEc!}yW7lmH<&(C0X9!LCq=&s8JR4dv%POf+=OxiFt zOSCK2u{+l_RUqL%@ZMZTM2^TN;0bo>rC+~e)tI!RC-13<#yYPMu* zfK^rLQkTL7ZkAV`4P!){uE&#WY*FCP>#zjoj;Cah7hAER7de;3N5sZUw*jyG6vp1p)-`{A7D92|!!I+t8>Qb?ad-Yd@j@E!UwMG|PBYOlE23liC~BL4i7gq)ZHCYk#EIz0 zt0*r5;ONFkDz#JkUP{^W1OEsjzWp@LpTtg`0ax9>V3_Wh^W)T)6l~lZr7Q!hCW-SI z)%rK`XTQzW6k@@hWIzOEn!zi5B-V0f=0!?)m^4@-@{baMB3#z1QAKL5g437|L{!ou zV}By=tztkyr&*^x5g)9Q{;g#9aYjxJ+*uaN@uh#`#SVw#dcbVo=dbIp0t~M9ZNKeN zHaF`Rs(VSwQckML3P&g_CrHTpQsHyCi)5}BE|@UqMy%+v7$efRW!dT&4ympIHZcwA z-?#_YRon#vpCG$u5(ClJWI$}uQ^9K?pI92tZ1J+H2~$cT?s<4Bn8)62D0S@oBG4v* zTMKXk3~W$0U+KE8O|+OwC0<#V%YQIfJRT~w509}?x;+-k2~;I{DwXHb7`0P7;z@Hn zDqkZ?L-xc=dB46d#>YC03P4YF-N&YOnotXAe^)3`^psfZJ1lY*EUlyLpcMUCsmVI? z$#_9@(E_zlwRV7CTX}xAsG$+_*0$b8$l?qgnC=&I2U757Hn|A9VdKM*F|+YcTDr9K zaaLf(vQ{;P(eu9D&i-i)c&{-!;Tl?sINBbx6Ur)Am=&e$EF<5n<3J|`9^fDkKQ@~* z*EDb0W9X6ETi3fxpdURQ=u(S0G20mPuqM&)o3SJ?8IBMZSW&Ulxv-QB^q>aT}Bvqs@Sz0Z!LK>JaWgAQD8?LJ|2GWo)W= zZg-_GMkra&+coh_g|6$W|HuXL7#AuGk`~);w${E(V+G6_U7&6q{{r_LqYZRW>Zx#Ez%&+19Az zKA|N4@e$Dy5=EFNy?-l@oA>3e3N|x4@D~Rq%R$thNF^rW6%Tf>7(JaS**MWP6~_&2`v5VDa`Cq*=kb9 zDt}&w88z>t^_K9`5AuE_P0y{FWlMEU2SD|P*M7?GBYp-trkWSkD)XtVAT>V#o)Fcv ziJK0)F`y=^laho>r*?}9;*0&Nl{JZVkaE?bPxW)nh2EjUz*O2;fZ5?phM3$*X)g_sb8!JJ(maj#d7%hK0GNj z2>fHUuuQJqhSQwI)^?X;wzshNyN>U7Y5GY53!#BpW(m147A!!3Tch~3YW zkzMgfK%WGl_*|$o7xT#S!I@Xc@F!i@#K7Kia4)J$?D*yV62$p}i4_ZW_b|?#z)4#d zbu&o#X*4l_wpLO~@E+I?bFi-GZFEGpzV_e%QV?|`x40OOcTIwvR~g}?_1r&dMLqfw z^T|qTpn1R}WGCe4mDH2(%Z(FNZ@|%hji`09jd|Hpzry+N@GZag#PNyx@)z4|DI7j* zQJF~cS`cov#OaUYDa^TF)iPz<^ohS{@#Y=Ao(&rWw+M81Ri7%nA0)?m;4YL~0rw1i zSMcVLfJDlw5mUdyNp99M`8yAkIeNimM|7-06gpx+chOv_NgGwpn>cW6fz zabsWX6Fv{07yc45gpMzYuI9xRCQbKVOd{wKn`!EC(|ZDe%Qm2I38;Sad9S)71pMd> zrBE?R&WF%YhJPaaB;j~9uNv_eiLTm&RiPcrQRMx`1|;d8gyKMw$E*ikzG@9+DoA*5 zmq>ne`A4Y`Zuyt1-eblloJ~98wAsHuUVgO=+1btD z(|jO+IVmpk8}ui(djvH7X!BKWChO7{5g>HzDAjj*V_uz_nQ0jrFEM=R?c?$_22uhB zHu}YNY>K(AWB6~4O&_d8Tr#bGSzpWCq;2XW2e30Kr}95$bF7?<-SeC&?pU0@->aOQ zk!qopee8wsb4N}FzpFY`20`>}-{%pAvPh^qA<4Pg^uUtk0UJ}n6DH+GQXkai-ef@H zm0MZ5N5UQxO3^Pp^R?~Ft5B+rMw3bGit};)gA`geqdk<)u}g)BV;brxj!v zMtoF6GmN~+&vDj*{zQDrw11I8`NR_b zCS6MHL>CBJHEG_*r6s^%X~Yw?5d%l`CT&CzpJZkCp6PIhQN9}u zI$gJX7?)0}rD!r2qB%1;3!YT0qkBFH^}U6g_XcK3ddl<}3k!=ke~HwEs0q7?8pg!$ zwDA}GoH9uJs%g+O{j~0HfR-;d+VN$-NFFi)n-!ve%;W^N(YUkfZxTqNG?F#vKXqu9 z_)o6`=6`G2mzj8J{FC!XBi<$A$0%Q8DQnpXGV`u)_3hi!$wYl}T)X6c=4=DoCk&g} zYdyw%?qa@Dq!bLirY;bfkxvVbBJYQjb4mKK3O%_ew(lWSoX!2IUbFz0gaYsW6 zE+r|cCcVS7y)}!*>Ut5b^Nc=(UuhRB)DT@eO%43odZj-HC-0#qe_!9sreH4kG&NOF zWmAB}5Hms+fk2v)*Tw(p1h#$-CG^*vb0aCAn1(QqQRYIE_nrs9&-@w zF}<2Yd}&HF2mo%Sa!9oI((pv~fn;R=u%2Ca(z5MMpbYN-s9q~UXI6+3w!8lwROtU< z^71+ex95*y(60G!WM-4Hc>Nd3hy# zW#YPW`wW`<;6Fe3&-wTtmxCyO%0o?{o$`yD7k8$)E=;zWUVPw}C@vu>+6#V;n*B3- zjW>P#51FfYoPomb!#nrpubTyl#pQp|=M;DQsCx8_w_>W`pN69d<^>W9H)7r?*Ar)nvE0G-a=NZFfFE!3Hijyu7I4y#YWS# zkJFqZ8spQA5q8vo22QGQPSaWcnt`X4<$3jXa51+6f6#1^(`DjlAHo%Zl9l(V|5(G&SgaU*V{ zn&vy!=QeT)+R6GYPohND?;UAYx5R7uNY#+yoE!ct#EiYWX`MQ;|LrPbaZkNI`1kn# zPdV7e+{z>Jr*ACNyC!F#?`X)F`R(C`{hI}yqn3R;1wXXD+}wiQ&Q3eJ)h|v;`uk*` z)|z02HTFaZ`GxST3bd0fRF@-ge7jM(xt^pDCjsgi?rn!q`M290lr1Ty-!uRYIODT( z>S|*J(kpHfVg+L-$T-oU55W7rfC0>bzn%TOTZC8?B~%+!b_>zI<}5I9}zvI85+ar}s4Csv3|JkF3H(oxr&3pfjd0ZG{nBNV&Qf;GI!eGjkPs zEcBsG&cdpb$TU&ovAbGYYgHfdc!CmduKbCX&Os>OgMw4Rhr%0;>En3XVkR|q=m+&3 z>qIr#R;04CX$sEVP?AwpG*QrTNmoi!m|}>EAa88zvI)s-kMkoe@64!Avb;Dyq%B3g zXexGxyE7pV!p3#z13}_oMJu!@S(I4=;ZZo0^prxNAH zE^?+eC??sI{iaQ-u>93IBXDjZ*A};Dy)z`hZ9IT<#_H@pdCAy@byP;vH1{;;p8d*e z?tjaM<#uQdn@b@11`;2DZhYNBv6q{+#`}(!QG{K4?8Z@}IkZ z2S_3^Rp%AxLD1B+D>3E!XvJdHpk{Dk%6>o4cYA+)u|e(O^5@K=o7#B~$7g0HYpCIF z1^KZF$jSRjL-Oe{0wCH1-mgO;(rl^q8LV|mr3v#MCAST?r`O>J1lgk_wd#9g#$<8Q z!@F?gP$pMtxD?eBr4|R4=2Ay^$;(g%bX^J$?#P*kuMxhE1UscS=a&_gF#&C0;!b=O z=s>I_qW2cRd{dD?o0Ow%`GT8x0dB_>!ooCVgmDQKxWc>|De4j6ohhkqRh~m!VG*xw zkBLtWk~6rCf92IK9m`+L@6X#R^_g2=St{D>qbZL)$-*>Zzir_60m#7xQ;8zkidofH zAAT6x=$o>dmu}^j;C7(HT?BzwsKTz?e#|HDce>CWU~N`|`;mn&bV1y+Zc>U+SgDXA z8)SIRb3&gIGT)b_p`O_%yrG8gh;>m$6K|fBL99l-?G^EQ$1G)y7O;)wySZ>|3Qzgw zvr{HH$U>$(DAAb4D`GA%YNPH$wt<1Wl<~^=bp5uzLt0)B!xXgx9MEh3<=bbDbyN+% zjj_wG@pQ3L@W8u8RSkom z?$iboN~Fr3zT44~Fma+hpa(#T!T22xzNW!BMu{9o7K;1-N_&QF&x9vjazSUvuu6SI zawvOXO^T`{Okk!A#}nK*iJC&RDEj3e>2weKw>NJXp$RbqJltGcl!}dx<=rm%%IWsX z=v#w#1bCHuf?EaMN6^3}tDYfSbi&g<&s5>5E}L4^k|^9IdB=Z%PuX=}x4Ht52C!2( z1XNc@P0H8LeSrDra$Z4G6%_4zCQ&rfd%R_V~oEc8`5#nnbTXVG7=-N>S_ zIGchR`Slw546;t!6Eg(NfX8JWrJ2j`C^U5bn4X zgA)RgfjifmcX)vOh@W4#zF+>CBBPRN8|7tRKlO|8W8;02vl8IDyQ>pgU<8m|HJV!q< zcWvNQIMTPlpokmZnp9ZJ^*~*5R#j7|7v&9Ad)M099`L&UqiYbFn=v+z zYqfui$)&r)nBA3_;qDD%4T{Tc{%WIYqa{Jxu*@H7H-gp*FvZ`ylwTKh3DKV>r_}uT zG9dV+t0XNxc{?R=-Vo^SlKMr9j9vRLmh|npS8@X4cI)JH)DZ9Z4Q{7S`_tVFmw^i<4{?u+sO*XcxW~Roa#U4)bb%I) zVEADar$CfH6U#l0d!w`OW|0wUP(2PZ1EK5?E}bR*J#Fo3y2 zu^yMS*Eh(|Yx|4d)1}z zC_hgb8T7E6!s~)weaPl0K*Xpv(Y|lVdq8`Kl|Bgl*xBXb)$yJ#{a|c`AJVcq&4!Bx z;rvA5^oA?iZBMQtAg3~cqdViHuAsMI!cM{DANEi_fk5kHHL8eEKW(;NBy7zu9H1#c~yV@!#5FWr26 zTORvYtYO-g3d;)P^Qr9>pwN23dxEZSK>Z1}o5kJ&3B3>-2C^>m{9vJGyJIdl3Up;#+8+4130c{P#`EgkS0-SKSDyJ0oa zcnHJgQnpaxdP}dqjh>*dh^!iij$D<9IFX7YjaoD4=NdAzWI5%NpFcn%ZRJ$mERcm| zb2)HNUlYlJj~LlWl^a_=_lx~`w(I)PMhSE$xTfVgB}7$#|XL+J0O6pz8af1umsNa zEO>rFdwJNNZ9VR8yg9p00)`MwsF}I@2lXASuJQ+-5>JQvW4h~Wn=~u;XKoH0!%VL4 zZ-8bf7fEFjDcplSKCG4e$NtUKwQ3Jkf;)h2nHmLB^f|U1X*fqfS-e5k`~3TE_e1PC z6Y6?*XsMJNrQGRIyns8BmOzNTR$*cK=4I21=g>tDF|LHj&KmU&9?&VNVZnY3nyT34 z)iWQOT~@zj53|}|{hnc=4MHi`$f_8`#)nJJRLV45cB~D>igWud4F0g+A{t}}`n0KJ zT2h)DnVM2=n7TspiZJ0<(UQxVPL((yai8R6*t~W<)T<&Yx0z0r@CH8nU0~c#2@=!a zDVX3Z{;(|=Joh6_i@~hZ8=DafW0hnT&qJjIl=R^4U+n*4)_F(PtAk9I**5xqN4&Bj zj!PlCFf@QAO1)p-q+$(PON&a>Csq-O_HT(J&bz4%yaNkd zOI$Hn>OxnZanQJ6oRUjEPbG@at$Y%Cu@EXr#}d+P>z+YtIB8#y2#|L^1q0Bg4<%nU z1XGR8)aYvLRR0Z-mwF0Tet8Q{??_Lf{BDzR0Ae-BgTJWsIQpG@GFjI4(ETwsk5Q95 zh|V)u)A5?RB%m(ZiIcM{)?a@wBqX3!F?Vu)Z~yQMF*`B!p23#^g~lo6IgFpQdD3xw z!nr;Za$L(+spV7dFt*KJ%v%XY`f07dH6u}3{#NR)8h{c&9tI%mkSM)S85S%{J*@E4 z;%6YDQN^-R(dr%1Ckh^10|0+Nct}Q;;ESdau$yOHVp6k}<)K#IYh6=wE0|%g{F1ms z(DHca19HJB`6ln$q;al-O4PW5_)==-By6*!AL<^pcdZuOH(q>EADP0fFBv&OY;YJkL({O{wRbY_$ii@k=L8sw zBHVo=v>Es`k;PaLuiGNySTXVrqdYuGk2K*CSIvQc{gj6|o>~kQm_M=#JcfE=bAIuW zlsP;4l9)rM`R}J$jLPNo6l^#dvM^&9VQ)|rHzj$wAsvlYnK9{_!JaUV^0&g z4%msb-QK6;wo3!KjC}N4_|vQ6$#F^4Ju#lXPh29&37PdIzHk2oH)CXVdRfB)l+N1ZXPB%w63e@`GJL%?3*c&QB=;}AYD!rd*=fGD_r z+@p^wUhv3RtY`7@qxEBQM|lQsCvNLQG$nDOr1cJPABYd!)?O}{%dl&&My$U@BjfZu zcv;P2?B?#;FjBcAGJPTG_WeU=jJMQOW;8jit$k)K zX(mPiwky;`yX;?eN-;#-7Am)5-d~&hK9siLiA#c$i%i?g@p)xy>Xkam_soC}`XV)% z^2UYWLA1Vn08OeIi{;E&nWhBO-Ey2+Yh7bc6z(<;=*qwMenG2JQNXmgqU(&6&A3}! z=o-NV5h+&SbX$(X5sL<{&N!iY$SCNPd-Xr2wY?=SfAntb5?JA);rOsKYUcCboln;9ro&{RVy{mq$Acyr&^||%!l|1rux;~DA@osZ89fh`htQ| z{mT#F>!n5b?1BhA7dT=*L{l>|e}Rk61qz)!Uz;#k?UnC7#Rbvg*B)B_ql9I9Jm@JW zF%w(r;o_p<$p6|Y9{pqFa?R7?f8JXi{{!PV+K4+zon2R@@@-yhX#1@cRQ!K27gL{y z;Qwx6|BnMDjN13%c_J|Z3EwMKF1zdl1ze$W^dbZp!MrSBg z&WT*l!GWCHo8$Q4efRN~?A&^f)aA;;DH*AxUCtoh2$P_$Oz(g#-<|Sw27uc^yu} z{SwE@qT~u4nH4U|#sxIMI2Cb%+yxbIN%c&*x4v~S{+Q~A?RghUcYbA<{teKP>LeC_ z>+aZtKITU>2(ip7|0$VQlQnvFeQvtKtIYWurl1y9Ou)WaCiQhA!HhJhaw_H|T8k_3 zep821X|Wqcfq|WDas5?!RrSQw#6548aYfH<>msK&JTw|p)BOX;&0GA&073hKI?KQn zXx}0{a_^zQo9138!TQ$Fxe!gY@P0vuH6kR+f=#T_-3wEtt-9Y()!)}YC%S<-8vQ`N z2q6Pp)6utB@PST!>7#Kfi^w_U46u+Nzpnw*YHV~!vLowM8_#caPKNc^(AL+pB%m8U zD`1lgu;lb3IBE_7LXcYwA8g8gufz=_t82H@z$s&DBoO2lnf~F{qFI4glJ@fy_z|kA zS>Gi_(bc?h^4>1_!?jY1ejr$$oky+uBR+z7q)y!8^I|M{lfJ-#SApN=lp^`c&X02? zYA~$d;N7HH5Je8>_CV^`E-Z!&XQ0Cpk0dnpCElR~GJv{@jp*%h<%rU#A3o^>Y_{m) zp2xc9=(@<-FxqY#cj&;x@ijto|5b?;r=ax@`}Mfp?{9Rz+kHco*WCNozrOwZGv|6A zJt$t!=DOG`?Zmk6T0-5U^BN}W-o^J2KhZ>plQ5_;26s2ai=WL4NNA2#kbra16;RSO=v0pN&@NRS@!4N1Qsxcu< z@A(loAhnv!j^Zzy1g|MhUI!*htd_tjwOJbN2MM7S4@t#rtT-XS%y{@f01bJ_IloR% zgOux7&14``V_lp{zfrfF+w6)1 z$dTNceZ}@Ma?$KPF?-PAax@Wd#>K;ycJ>c%l(g@I{$mSwNe`k@pJ*xOR5 zK|l=$;M)jvK69dOl;+ihXBsU*!o7WAs3bh=<1GR1Z1qvHXNZ;FI4h&lJf@7*U%H>w}0NlYI}2GNaw%~UuPIlA>!aEoCNix1M? zpuG~m*-|F0Wg-XszFO@47|%4`*BGAD91CFIp%bAKA?L+MBG|@8KOtRM6)!xZdk1WL zm8c-u7vLm4$x$c&at(*IRy!@TH31Xl_!w7HhwXWgy_mabxnI3+$B~rGUCIcI%nsRq zY41Cun%dfR!O%;j6GA}TH0d1!1O;iKg)S{17?3Ii0@9RCkq!ZZgdU`Kl-?{LT?k0; zy+-SrG==x|4mB_M;NCS`92^XrLqas@QTzddJqFQGaT?IBSqR>)L; zfKwHLuc+GWHjMW+V)~TkyJ78HQLn5L5)yOhsGL4CKw}g5drmc|fS>k;;U&Hwul^zR z=lkEtYzj8H$FtjiycK91VRyJ#E)3e{>=$PEDs$!R;gu>YP6MXQf8jPfC;yWvBjK=; zl~pq)@>AKO=fHH@;LITZ#?d-IZ<@{3U{UB#nL3++1L3lTP8IN)ZGT7Z1EuF60IGKw z5Un}v&i@mF@3%HIv89i#r>ltn;*t#X_#?4AHWnA9z{jk}@kvy;K~|Cd_}xsIG*^xe zx|}Qk&KYJyQpvM6p8}MZk2)EhOw2hylBJOk@!yE)C{9;2Qq-c%&5b2YnQ{2zb&Q6R zb`>*lxJ| zxvWzJlpX(h+)$_Ppk;iUQ!&e(L|^YJbTw_5eK%lgfYAvf0G!^aI(~W<$Xc!ejEau(T-F zfnZox-1WV5X?Lf9>y??YBM6E7ZmZbzgvvQnt_UwGW_PQ*{84GZQyLLin6LOj|0M|J9{~hdF_X^UsJ;3sc7==d`Sb@bzYJ3 zJvFXlbThV6KbsD~H5+*BrVT1iu5;_tv)$r`pH9Vf^a_)4rYvjEFf4X8G#~CxGm!9> zU>o3H6bR?^#oZBds71AO99gg6f$Y9s2oF45=u z3qFqx;1(-c1MHPb5A$#FH!-$ElHsRVpFT0O%d*mbg<=EBjzCqUzEpHzJ33QTrBdf@IpONoStM} z`mM*O0><5CA02^_4RBJR?i(q_who3>B%ILYX$l?1(rQ&m%7g*5MAKR#kEI80Su@+A z`==-Fx#!ubYfF=K4E+mcFB0Q*q!gaoRq(DqNRLCDG%NMIGq!7FJk^B+8rGWI9LwXs zs=9TOwZ3@2g6(WgvRjnlEplBS^aQidAhc?HDQpU5`42~gm|iS&2@A=!*0&p~Ty<3p z#3hgJ9wVsl|2D(Xbb=3w>}K7Z8gU zl@`dCIwN!O-$=Hp4wfb^f^#aW5@xd$SntqH&p8)%UzHO*hL9jMTvn_PT>tG@<-hf} z~#lnGJ1F{ zn3G~P***F4--7^HEzRM*KDp?h_;c#ymmO_2dVPPul#P(Tf1hk6*x8GWP9-@!(U|bW zLmxbJ#Di?xBE$hR5ckviw29K??d;6>Tn7c`b?Sf0q-rMO?yg=raC5> z)R!3n=yR4&QBxB-Z<4uL^%0EA{F{Ql+_YIy!I-ORkv^J$*4J!7wB)(|D^j%7N8Fm(M4}&r2llZi!$64t2fG3Ed<4xP8QN5`({( z|LBaFpBoh9E4C@6xFs4v?-g;l3Dni3Vu1_fWojhKDU`FmH24;)vd*mY97n0%Yte8< zIGg;90Bc&|bO@-^U7Nl3&HhK`Zz*qUZ+~k0BHmG|txcU!f9Ye=b;>B&ptM#ud>*ce zG&hYgFBOj>12e0|anXYRNp|(Jb%>^NT%k|mEaA{eTZiMn+CTrDc>Vw3J2>EzaEx5l ztEQzRM_;~Ah3BlhrP{2=e4p-pZzJBsev|pr{{P-kc%HudI;E6tZ_A=%t7*ALn>_Yx za@YR3BI=8v7p0I?JYF?A$7-M0^$TlQ#lWq8ZC~$J-4NrUjl06x>-E6BXYx3NVfh6| zHn-!;to^2wTVCTfhF@*JUsLkD^ZACu#lXGd@$Mfl)KM}MZtGU%?DVG6m##7&-1Rro~FSF*CG~v|hze?7v2;{qDex*}435{9%dY|tG8wqQ?I(zo^&h5m| z_xFmf_1kX9X8z+Tx}Rd?ik|+?>Gt%UCF8iQ;a9=$6}4p-tbhJp&EIYFcfa}naWL?F z=OE7onuU@7m=|9EGi~x~=>N&k^v+qFdau^?Lh{e6x#zR;mt5hrMB9z97;);gTH$|L z+5TyLp<%#IG!yCtLVeL@)SHzOfDhG--LEwqIY|PEHht-DZgSJKbK&N=28Szt~mqyYBNKxHnLwUaUNs2=Sf}Ksjo=5P|`!vB=gR-@=#FZL0~i zhNg%j!JV-D@yrwHhzq(Qa$m~R zzVSYWr;M>g%yDnKNoA!A=77d%R+KskX42ZD@0lw+**a%V|c3=F zIa;=;UdAS?XO_KP;eyR5-quiT7z^oEf66}UycKOiIrH)*CokXq%CuXadvXXZ04b!}O!iezo>PUSdQSG5C#1rUqB(?$e<3MSRru6F3LUwvr1Jy)V z!)D5ibE8U|em9zHNRQ9sM?`e*wlnig5$ir}Qb5`z-mrUjj9RrZRD(N1#C@jCCtksL zN}qM4cVI>BOHyx37s@SJ}Xv% zd9FF+e1s(gN&$S_PT4KiDdkaeug2Hk{-NxWDl!$fIPCh^d2v`eRT>B!DM+K-NaGLL zi&{h1N4wmws;%tOzGpW_8+%;#_`blG(zhVz$t{8akXBIQ$(bu_Sz^xDm%~(M@!7-R zYq3n|t-|89?i+3m_M)ZxFNz{8KFa&d6Pc&&>}voJbjYP%HvJp%4DV*C?5??G@sDCP z^|;B8<$Tr4g>h8k|)9ru+yoJ0p{F%6g{Tvb`FBe z!1Albp(SxjEd|+40kNY?k0sOCe%HeT(!iP&5t;xH3`&3?+z7)uW|Kj6l|k_Cte+xg zmCO$JGJ9SJ1?mA|nfcF`r2O~HFacTOy_O`<{zt*cS_i{};L=awO>?}yj=K8FPy z+U4TIpc@i_P{}O#&^#$~)ALKC)#2k7KkF%jcdjTS z*9r9%Yd$0ALFF?Ip*C28-Rv;Zs}#2>R9%O^QMp_BK@{y%G&|DS(<{Aerzv#K)@d0g z;f9T}gYJKwdVlf*yx_<62TqL7*kclO9?P5KQ zs|0pmOqtlC>LGE7-mfUwEez|VY_e**-ol*F$1WltxEF~AYjmsFkm@SCl+VoWkm`m5 zx+*#*BO&H-ly&t}c(T5?9R^PtXV09Zj-BQoY+Tako&WZ_9?R9xLllUj~lzzQlTzumr^+diMHWP%{L zeycdSg{2$>fM34&Cf!)y@ItA7Qxh>da2op5Sj{hb5bC8VnlQ*_KvX7b&*$(TjG?ra z;^2EO>Kn&Ep|eJfF$_U4{W@|`pCiy>x>@aste4~FX7EiY1$*S^>7aa*ijH}oAz!mq zqy4wg;<}^d5neFja4WizhEg&Jwk7;FPOfs^_Y7yOnYcTx{Z6b@9(U*y(9je~g5cxS zJ980$_I47}+P;Uao{otjs~?tbiPx|rZ6dO;$38SS-aOZj{i(L@DjO6^_xU-kn;?~o z)0g30gqa*wUkj52vX|e2L^K`C#JY$3h85K%(XX!GA z`xe@KgMHrJx%&<&9R#koGIEl~aQV{w6=@a>BnOiLvTBM^axrAjF?)YL@6zRDX_ePOZ4blb zGBMRI+hq&#ioREVMZKu`5}OF*u*L%#D4crz+Z|d3jAF|0RV#O+8Wx)g2of37AY)Fp%q^b`6#4&iqaTd%+}?;dn&tvYImf>Y&bAB5yT!iC^6 zU>wcW_>vh;HlH1_GnH|9hr_8LR9Yf9H}F4 zvXFq=eD`UPNCZLMn94Jl^3zr1?+s4j4z7@vD^cd)bW(A!-1dvBy#>rrwDCK~RiBEUv#nI9e4(smK6 z&)#oQl_XY_Gp!mgVoe%>>~_4MQjA{dcH`k$H7;I$@OWTN|8;ns?{b?(%N4#1tO{9j z#9Yk^5|}=td~LFi$m%*KmCz3O#rhush+sHQ)n1bFBvc349o<<|JTtz@+^2i9(+xDj zGkh_Y-iI@cb049nZk(?sm3Gc}*40!ceZ}>&=amlel*P0MNK!yS1_v0@8$z@hyLJM^rD9f-x&_w%#Ip5Z<#iA2pYJR^hweN@)kP1vq|_T)L7ItC@IY^{P)d`Sy3D{U5wmU4yxoy8uI?R3(T>I3i^Lzi!rD@j0k~E@N?t}R z#Y*<~IDT-viYV4v7faOPODE0S)!9gCI zjW$-!vK`G8^f7nY>8jD$ytv*=HkPcWs&akh;;H2B&IN+t=30&Xv<@9pZVb-E2 zer(WUg1&@c8=0k6KoK#yF2BF}i8N;NR(z2tbhrqz@e<#5GnCuMsp1veO0xV`VUdH_ zjM+n45TiGC#3!Mt6%4)avQd|repAa4tWOcy{YB-NmR2w-ZOJ1A<=L$Ec!BBp$45$d z8aJLEQnLTX;Hx^Hrxh}R@7{<^^iN7WNE?Kt%1#p%#+q0uN2iG}h=yR~EN_8EyHA!_ zJ&Qt+zNCT<)w5^Eqc2j3S;3P>5B;ta!zf3vG$HxByT+-F`b?(7`hvwtYOSip=Cdx_ z>z*5#=tqxMp35~%%SG#1Wtz8iIJtXtKavO74;E6??y#k^^{gCOeVDQ@Js|TuT3RVP zOr3&e6KLv$BVOs!gvr}M*)&0F4@oD7_%|cy>ME?R9>=p&P{bplu=eJY^$@_kivPQP z$rkg*+#BFwz;9vO&Z}=tG11WlH7diiM=FP=O>T$jgSHUGlvvg7+0l9Aes9FK?4;c2 z9%u~VpZ<(f+N3G#;@drUW7ox6i(@;XRRhNr(a0gc0rkuLA2B%B(~zRt18#lcsz7eI zSKrvvL20|254~KN)RA2gV}-Zs$Z@eNOfqK{^a_VVk^%0%N$@~|>w}o5Uj}A%)+eDSsK`sZn#XLd#y&HQ%`VMt z0HM7cYmpyO$KM|-8!_C!H(>FKHEjc14%u~qVrpVlGG9$jfd@jEVFhDERpOI1lZ)x%q+53AgPJv z8UtrYjL<_=V^6XRYRBnhQ=)N1ow<7b+|p9@kq0Ie**JcEoMM7^iS;8Sc54T^1(R)M zjH$+L)RZ;qQ$9%f&AOR#5K0k2K6o0E2H!?kRFozXZ12%wj4CYhYVmssLN}p2LKzYA z!TB|h&8?MZ>Voo8EIyg3K1dK@3N(EpEzbu@^#IOAL3n!M>vovbv^JL7qUMP^9!947 z`)i8eJqln7kDxlL6eTLkaA`zFheoo77AN(aX>*iw*Yxp|DRImNO6X%8xwAEO*%@Am zu$Vo4_k#W@hqG+WJ7;Q;k@(5q1^=B*686iNh`l>!T$VBKhdM^Q)~3=qV!3k0PN(kZ z9GZBQJF#q+lixYGTAQP|Dmc2&aYObWmuE1YBX)YNU-`e2|MhmDgXxgYXcJ;c&XnBk qwYE&K- Date: Tue, 13 Oct 2026 21:12:26 +0800 Subject: [PATCH 02/26] docs: plan staged MSSQL SQL import implementation --- docs/design/mssql-import/design.md | 2 +- .../mssql-import/implementation-plan.md | 182 ++++++++++++++++++ 2 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 docs/design/mssql-import/implementation-plan.md diff --git a/docs/design/mssql-import/design.md b/docs/design/mssql-import/design.md index 1c84890..5bb79cb 100644 --- a/docs/design/mssql-import/design.md +++ b/docs/design/mssql-import/design.md @@ -2,7 +2,7 @@ 日期:2026-10-13 基底:master,d45c903(已合併 MSSQL 匯出修正) -狀態:使用者已同意四步畫面原型;本文件供正式規格審閱,尚未進入實作計畫或產品實作。 +狀態:使用者於 2026-10-13 回覆「好,進實作」核准本規格;[書面實作計畫](implementation-plan.md) 已整理,尚未修改 importer 產品程式或執行 DB 匯入。 ## 1. 需求與本次範圍 diff --git a/docs/design/mssql-import/implementation-plan.md b/docs/design/mssql-import/implementation-plan.md new file mode 100644 index 0000000..858da04 --- /dev/null +++ b/docs/design/mssql-import/implementation-plan.md @@ -0,0 +1,182 @@ +# MSSQL SQL Import Wizard Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 以專用精靈安全且有界地執行 mySQLPunk 大型 MSSQL SQL 檔及一般 T-SQL/GO,提供 Punky、錯誤紀錄、取消、可信進度與 ETA。 + +**Architecture:** 同一唯讀檔案 handle 先完整掃描,再由單一 owned SqlClient session 依序執行 GO batches。reader、native 格式辨識、session adapter、worker、log/ETA 與 WinForms 各有獨立責任,保留既有 exporter 的 LOB/Geometry 協定。 + +**Tech Stack:** .NET Framework 4.7.2、WinForms、System.Data.SqlClient、既有 MSBuild/smoke runner;不新增套件、WebView 或外部 sqlcmd 執行依賴。 + +**Spec:** [design.md](design.md),使用者於 2026-10-13 回覆「好,進實作」核准書面規格。 + +**Status:** 書面實作計畫已整理,供最後範圍與步驟確認;尚未修改 importer 產品程式或執行 DB 匯入。 + +**Execution:** 保留先前選定的「分工實作並逐項覆核」。一次一位 implementer,各 task 經獨立覆核後才接下一項;最後整體覆核。build、native UI 與 DB tests 由單一 owner 串行執行,避免共享輸出/fixture 衝突。 + +## Global Constraints + +- 保留既有編碼/BOM/換行;不碰 unrelated `mySQLPunk.Desktop/Properties/`,不讀取帳號 token/瀏覽器 session/已存連線或登入設定。 +- 只替換 MSSQL 的檔案執行入口;其他 DB 引擎及查詢編輯器不改,`IDatabase` 公開契約不擴張。 +- 單一 GO 批次上限為解碼後 32 MiB,即 16,777,216 個 UTF-16 code unit;不是欄位大小上限。不能插 GO/依分號硬切。禁止整檔 bytes/string/AST/batch list。 +- 嚴格 UTF-8 有/無 BOM、UTF-16 LE/BE 有 BOM;保留原文及同一 session。支援獨立 GO/GO -- 註解,拒絕 GO n、同分隔行 block comment、SQLCMD 指令與跨 DB 的直接 USE。 +- 預設不略過錯誤;略過對象為失敗 GO batch,不是單筆 row。timeout/斷線/log IO/未知交易/native LOB 失敗仍停止,不重連、重試、重播或續傳。 +- 專用連線明確指定 Initial Catalog;ConnectRetryCount=0,單一 command,CommandTimeout=0。狀態查詢 5 秒、cleanup 10 秒,取消 10 秒無回應後只嘗試關閉本次 owned connection。 +- 不新增全檔外層 transaction、不自動清庫/DROP 使用者物件、不改 SNAPSHOT/recovery model/constraint trust、不 GRANT/KILL。 +- 所有走到 EOF 的作業都做 session/交易/digest/已初始化 LOB 終態檢查,包括已略過錯誤者。native LOB 結尾要求唯一 state row、Failed=0、Consumed=1、Sequence=ConsumedThrough。 +- error log 預設 `%LOCALAPPDATA%\mySQLPunk\ImportLogs\import--.log`;略過前落檔並 flush。UI 最近 100 筆或 64 KiB UTF-16 文字,先到者為準,完整路徑可見。 +- 進度與 batch/line/byte/error 統計為 Int64;command/result drain/狀態處理完成才更新確認邊界。affected rows 不能標為實際匯入筆數。 +- UI 約 200 ms 合併更新;ETA 約 10 秒窗口、至少 3 次樣本與 2 秒觀察,5 秒未確認或長指令/索引/核對中改為未知。 +- Punky 自動 loop,聲音首輪一次、可靜音,沒有播放/暫停按鈕。取消、關閉與 late callback 沿用 job generation/owned resource 模式。 +- 測試用既有 `mySQLPunk.SmokeTests.exe`,不執行/重建 ReportExportTests.exe,不調整防毒,不 push/merge/release。 +- 大型 SQL、DB files、logs、manifest 與原始驗收證據只存 C 槽 local-only,不進 Git。使用者實檔/Transfer 不受 fixture 自動清除權限涵蓋。 + +## Review Focus + +1. 批次間安全查詢會改變 `@@ROWCOUNT`/`@@ERROR`:Task3/4 明訂相容邊界與跨 GO 測試,不能宣稱保存所有 session intrinsics。 +2. 一般 SELECT 回傳數百萬列或 64 MiB LOB:Task3/6 逐結果串流 drain,可取消,未 drain 完不能確認 batch。 +3. 同批先寫成功再出錯:Task4/6 同時驗證 stop/skip,保留部分寫入說明與所有 SqlError,不虛構 row 成功數。 +4. 取消與成功、狀態查詢、COUNT_BIG、log flush 或 form Dispose 競爭:Task4/5/6 不提前宣告取消、不釋放別人的 session、不啟動重疊工作。 +5. native DataOnly/偽造或缺失 header/footer/job/失敗但交易為 0:Task1/3/4/6 保守分類、驗證 GUID/終態,不默默改為 generic skip 或完整還原通過。 + +## Files and shared contracts + +所有新型別 internal,位於 `mySQLPunk.lib.MssqlImport`;下列介面是 tasks 交接契約。具體小型 DTO constructor 可採唯讀 properties,但名稱/單位固定。 + +| 檔案 | 責任/主要型別 | +| --- | --- | +| `mySQLPunk/lib/MssqlImport/MssqlImportModels.cs` | Request/batch/scan/progress/result/error/target/session-state immutable DTO 與 enums | +| `MssqlImportInput.cs`, `MssqlGoBatchReader.cs` | 唯讀 handle、strict decoding/SHA、bounded lexical GO reader | +| `MssqlImportScriptInspector.cs` | native 格式/job/batch role、unsupported 指令與直接 USE 的 lexical 檢查 | +| `MssqlImportLog.cs`, `MssqlImportProgressEstimator.cs` | 完整串流 log、bounded tail、速率/ETA | +| `MssqlImportSession.cs` | owned SqlClient adapter、metadata/transaction/LOB 狀態、result drain、取消/cleanup | +| `MssqlImportService.cs` | 預檢、順序 worker、skip 政策、EOF 驗證與結果組裝 | +| `mySQLPunk/MssqlImportWizardForm.cs`, `mySQLPunk/Form1.MssqlImport.cs` | 四步 UI、MSSQL 入口/目標 settings snapshot | +| `tests/SmokeTests.MssqlImport.{Parser,Worker,Integration,Wizard}.cs` | 沿用現有 partial smoke 類別的測試 | +| `tests/Run-MssqlImportIntegration.ps1`, `tests/Run-MssqlImportTransferTrial.ps1` | 隔離 fixture/實際 Transfer 試跑,兩者的授權與 cleanup 完全分開 | + +表格中未寫完整路徑的 backend 檔案皆位於 `mySQLPunk/lib/MssqlImport/`。 + +- `MssqlImportRequest(Guid jobId, string sourcePath, string databaseName, bool skipSqlErrors = false)`:不含帳密;`JobId/SourcePath/DatabaseName/SkipSqlErrors`。 +- `MssqlImportBatch`:`long Number/StartByte/EndByte/StartLine/EndLine`、`string Text`;byte 區間為原始檔案的半開區間,不能以解碼字元數代替。 +- `MssqlImportInputException : Exception`:固定 `string Code` 與 `long BatchNumber/Line/ByteOffset`,讓預掃描失敗有穩定診斷。 +- `MssqlImportScan`:`long FileBytes/BatchCount/MaxBatchCodeUnits`、`string EncodingName/Sha256`、`MssqlImportScriptInfo Script`;不保存所有批次。 +- `MssqlImportScriptInfo`:`Kind { Generic, NativeSchema, NativeData }`、`Guid? NativeJobId`、`long? ExpectedTables/ExpectedRows`、`string SourceReadMode`、`bool HasLobProtocol`;native marker 候選毀損是預檢失敗,不降級 generic。 +- `MssqlImportInput.Open(string path): MssqlImportInput`;`Scan(CancellationToken, Action): MssqlImportScan`;`ReadBatches(CancellationToken): IEnumerable`;執行第二輪可取得 `ExecutionSha256`,物件為 IDisposable 並持有同一 handle。 +- `MssqlImportSqlError`:`int Number/State/Class/RelativeLine`、`string Message`;`MssqlImportBatchException` 保留本批全部 `IReadOnlyList Errors` 及 `bool OutcomeUncertain`,原始 exception 不送 UI。 +- `MssqlImportSessionState`:`bool IsOpen`、`int DatabaseId/TransactionCount/XactState`;target identity 另含實際 ServerName/DatabaseName/DatabaseId/DatabaseCreateDate/Version/Writable/metadata 可見性/user object count。 +- `MssqlImportLobState`:`bool Exists`、`long RowCount/Sequence/ConsumedThrough`、`bool Consumed/Failed`;native identifier 僅能由驗證過的 GUID 產生。 +- `IMssqlImportSession : IDisposable`:`ReadTarget(CancellationToken): MssqlImportTarget`、`ReadState(CancellationToken): MssqlImportSessionState`、`ReadLobState(Guid, CancellationToken): MssqlImportLobState`、`ExecuteBatch(MssqlImportBatch, CancellationToken): void`、`CountTargetRows(Action, CancellationToken): MssqlImportCounts`、`CancelActiveCommand(): void`、`Cleanup(): MssqlImportCleanup`。同步方法只由 background worker 呼叫;adapter 管理實際 async reader/Cancel race。 +- `MssqlImportPreflight`:持有 Input/Scan/Target/LogPath/Passed/固定 Code 的 Issues;IDisposable,重選與關閉時釋放 input 及未用的 job log;Run 原子領取一次 execution ownership,重用同一預檢拒絕,重複 Dispose 安全。 +- `MssqlImportService(Func openSession, Func openLog)`;`Preflight(MssqlImportRequest, Action, CancellationToken): MssqlImportPreflight`;`Run(MssqlImportRequest, MssqlImportPreflight, Action, CancellationToken): MssqlImportResult`。Run 再核對 target;factory 每作業開一次專用 execution session。 +- `IMssqlImportLog : IDisposable`:`string Path`、`WriteStart(request,scan,target)`、`WriteError(batch,error,action)`、`Flush()`、`WriteEnd(result)`;failure 直接向 worker 冒泡,不能吞掉後繼續。`MssqlImportLogTail.Add(string)`/`Snapshot(): string`、`long TotalErrors`。 +- `MssqlImportProgress`:`Guid JobId`、`Stage { Scanning, Executing, Verifying, Stopping, Finished }`、`long ScannedBytes/ProcessedBytes/SuccessfulBytes/SkippedBytes/SuccessfulBatches/FailedBatches`、目前 Batch/固定 Phase/可選 TableName、TimeSpan Elapsed/TimeSpan? Remaining/DateTime? EstimatedFinish;bounded string RecentErrorText/LogPath、long TotalErrors、bool LogTruncated。`MssqlImportProgressEstimator.Observe(progress, DateTime utcNow)`/`Estimate(DateTime utcNow): MssqlImportEstimate`。 +- `MssqlImportResult`:`Status { Completed, CompletedWithErrors, Failed, Cancelled, CleanupUncertain }`、統計/LastAcknowledgedBatch/UncertainBatch/LogPath/Cleanup/ValidationSummary;`MssqlImportCounts(long tables,long rows)`。`MssqlImportCleanup` 記錄是否確認 command 結束、session 釋放、未提交交易 cleanup 與固定 issue code,不把 Dispose 呼叫等同伺服器 rollback 已完成。 + +## Planning decisions that must remain explicit + +- 現有 native header 沒有 mode/job manifest:使用 exporter 固定 Source read mode/空庫提示、實際 lexer token 及 footer 共同分類;LOB `#mp__s/_v/_c` 必須與 footer job 一致。不新增 exporter 格式要求讓使用者現有 4.17 GiB 檔案失效。 +- 現有 `OpenMssqlSession(settings)` 已開線,不能事後補 ConnectRetryCount=0。Task3 新增 importer 專用 pre-open option;其他 callers 維持原連線行為。 +- 一般腳本可跨 GO 保留 temp tables/SET/IDENTITY_INSERT/transaction;為了偵測交易與目標變化,插入的狀態查詢可能改變 `@@ROWCOUNT`/`@@ERROR`。v1 不保證這兩個 statement intrinsics 跨 GO 保持原值,文件與 generic-script 預檢說明需明示;這不影響 exporter 已產生的腳本。需要在同一 batch 保存這些值的腳本應自行先存入變數/temp table。語義依據:Microsoft [@@ROWCOUNT](https://learn.microsoft.com/en-us/sql/t-sql/functions/rowcount-transact-sql?view=sql-server-ver15) 與 [@@ERROR](https://learn.microsoft.com/en-us/sql/t-sql/functions/error-transact-sql?view=sql-server-ver15)。 +- 現有 export integration runner 硬編碼的 ignored fixture manifest 不在目前 master。新 runner 採明確 `-AuthorizationPath`,驗證既有已授權專用 LocalDB 名稱/C 槽 fixture root/owner token;不把缺檔當已授權成功,也不去讀 Codex 帳號設定找憑證。 + +## Task 1: Bounded GO reader、檔案身份與 native 格式預掃描 + +**Files:** Create `MssqlImportModels.cs`, `MssqlImportInput.cs`, `MssqlGoBatchReader.cs`, `MssqlImportScriptInspector.cs`, `tests/SmokeTests.MssqlImport.Parser.cs`。Modify `mySQLPunk/mySQLPunk.csproj`, `tests/SmokeTests.cs`, `tests/Run-SmokeTests.ps1` 的 explicit source registration。 + +**Interfaces:** 產出上述 Batch/Scan/ScriptInfo/Input;inspector `Observe(MssqlImportBatch)`、`Complete(): MssqlImportScriptInfo`,保留有限 metadata,不保存完整 batches。其餘 models 在使用它的 task 補齊,不提前加入未使用的空架構。 + +- [ ] **Step 1: 加入並跑失敗的 parser tests。** `MssqlImportParserPreservesContexts` 驗證字串/雙引號/方括號/巢狀 comment 中 GO 不拆;1/2/3/7-byte buffer 切在 UTF-8、BOM、CRLF、`''`、`]]` 中間仍原文相同。`MssqlImportParserLimits` 的斷言:16,777,216 code unit 的 Scan 成功且 MaxBatchCodeUnits 相等;16,777,217 時拋 MssqlImportInputException、Code="BatchTooLarge"。 +- [ ] **Step 2: 實作固定 byte/decoder buffer、bounded current batch 與 lexical line candidate。** 不用無界 ReadLine、ReadAllText/ReadAllBytes/ReadToEnd;strict decoder 的 EOF flush 要抓無效序列。明訂 EndByte 包含目前 batch 的 GO delimiter,但 SQL Text 不含 GO。純註解/空白尾段不送空 command,其 byte 覆蓋只在 EOF 驗證通過後才計入最終 ProcessedBytes=FileBytes。 +- [ ] **Step 3: 補 unsupported/native tests 並實作 inspector。** GO n、GO block comment、SQLCMD 真指令、跨庫直接 USE、未閉合 EOF、無效 encoding 拒絕;字串中的相同文字不拒絕。同 DB USE 可接受。native Schema/DataOnly/無 LOB、正確/缺失/重複/溢位 footer、錯 job、偽造 GUID、header 不一致都要測;native candidate 不可因缺 footer 轉 generic。合法 Generic 不要求 footer。 +- [ ] **Step 4: 以同一 handle 掃描→rewind→執行第二輪,測 SHA 一致與 FileShare.Read 阻止一般寫入/刪除;檔案重選 Dispose 後可寫。** 原始 byte/line offset、無 GO 的最後批次、僅註解檔不產生可執行空 command;大檔統計使用 Int64。 +- [ ] **Step 5: 驗證並提交精確檔案。** `MYSQLPUNK_SMOKE_FILTER='MSSQL import parser'` 跑 `tests/Run-SmokeTests.ps1 -Configuration Debug`,必須 matched tests 全過;`git diff --check` 通過。Commit `feat: add bounded MSSQL GO input preflight`。 + +## Task 2: Durable error log、bounded tail 與進度/ETA + +**Files:** Create `MssqlImportLog.cs`, `MssqlImportProgressEstimator.cs`, `tests/SmokeTests.MssqlImport.Worker.cs`;補齊 Models 的 error/progress/result contracts,註冊 sources。 + +**Interfaces:** 產出 IMssqlImportLog/Tail/Estimator 及 terminal DTO;log 可注入 Stream factory 與 clock,測 IO 失敗不需修改檔案權限。Estimator 僅消費已確認 progress,不推測 affected rows。 + +- [ ] **Step 1: 加入失敗 tests。** `MssqlImportLogRetainsAllErrors` 寫入 1,283 個多 SqlError detail 的事件,磁碟都有、UI ≤100筆且 ≤32,768 chars;單筆 >64 KiB 不截完整 log。唯一檔名 CreateNew、UTF-8、包含 batch/line/byte/codes/path/job,沒有整個 SQL 或連線字串。 +- [ ] **Step 2: 實作串流 log 與 tail。** Start 必須在 DB 寫入前 flush;每次準備 skip 前 flush;create/append/flush/end/Dispose fault 均可被 worker 看見。TotalErrors 不隨 UI 淘汰減少;不累積所有失敗批次,log 存開啟/資料夾/複製可用的真實路徑。 +- [ ] **Step 3: 加入並實作 ETA tests。** 暖機少於 3樣本或2秒不估;約10秒窗口;5秒停滯/Indexes/Verifying 回未知;有 skip 時 Processed=Successful+Skipped、成功比例獨立;read-ahead 和執行中 batch 不算確認。測 Int64 >2 GiB/高 batch 序號、clock injected、200 ms throttle 不漏最終狀態。 +- [ ] **Step 4: 驗證 fault assertions。** `FlushFailsBeforeSkip` 預期 `NextBatchCalls==0`;密集錯誤10倍數量下 tail 記憶體固定;UI 文案顯示完整路徑且不冒稱所有資料成功。 +- [ ] **Step 5: 跑 worker filter、提交。** `MYSQLPUNK_SMOKE_FILTER='MSSQL import worker'`、Debug smoke 全 matched tests 通過。Commit `feat: add MSSQL import logging and progress estimates`。 + +## Task 3: Import-only owned session、target preflight 與 bounded result drain + +**Files:** Create `MssqlImportSession.cs`,補齊 Models 的 target/session/LOB/counts/cleanup;Modify `mySQLPunk/lib/ConnectionConfigurationService.cs`, `mySQLPunk/lib/ConnectionOpenService.cs` 的 importer-only overload;tests Worker/Parser 與新 `tests/SmokeTests.MssqlImport.Integration.cs`。 + +**Interfaces:** `ConnectionOpenService.OpenMssqlImportSession(Dictionary): MssqlOwnedSession`,在開線前套 `ConnectRetryCount=0`、`MultipleActiveResultSets=false`;原 `OpenMssqlSession` 行為維持。`MssqlImportSqlSession(MssqlOwnedSession)` implements IMssqlImportSession,owner 只釋放一次。 + +- [ ] **Step 1: 加入失敗 tests。** importer builder 明確 Initial Catalog/retry0/MARS false;舊 caller 既有值不變。使用 fake owner 驗證取消、初始化失敗、Dispose race 只有本次 session/SSH lease 被釋放,樹 provider 不受影響。 +- [ ] **Step 2: 實作唯讀 target/state/LOB probes。** server/DB id/create_date/版本/writable/metadata 可見性/object count;必要能力不以 sysadmin 或 ALTER DATABASE 一票否決。NativeSchema 非空/無法確認空庫擋下;Generic/NativeData 不套空庫要求。所有 identifiers quote,LOB temp name 只由 Guid.ToString("N") 組成;state query 5秒,lookup 不能讀任意帳號設定。 +- [ ] **Step 3: 實作原文 ExecuteReader 與所有 result drain。** `CommandBehavior.SequentialAccess`,涵蓋 ExecuteReader/Read/NextResult/reader Dispose 的全部 SqlError;不建 DataTable/回傳資料集合。CommandTimeout0,token+Cancel 包住啟動與後續讀取,保留目前 command 的可靠 ownership。 +- [ ] **Step 4: 實作及測 cancellation/cleanup seam。** 不在 active reader 尚在跑時發第二條 status query;cleanup 獨立10秒,不使用已取消 token;關閉本 owner 不宣稱 rollback 已完成。一般 GO 跨 session 測 temp/SET/identity/transaction;另測 @@ROWCOUNT/@@ERROR 邊界並更新 generic-script 說明,避免不實相容宣稱。 +- [ ] **Step 5: 跑 worker/parser filters,提交。** native live cases 暫列 Task6 執行,不能以 fake 通過冒稱 DB 通過。Commit `feat: add isolated MSSQL import session adapter`。 + +## Task 4: Sequential worker、recoverable skip、EOF checks 與取消結果 + +**Files:** Create `MssqlImportService.cs`;補 Worker tests;Models/Input/Log 僅做必要整合,不改 exporter 協定。 + +**Interfaces:** 完成 Service.Preflight/Run;Preflight 保留 input/scan/target identity/已建立 log;Run 在新專用 execution session 重查相同 server/DB id/create_date 與能力,所有 batches 同線。 + +- [ ] **Step 1: 先寫失敗的 fake-session tests。** `DefaultStopsAtFirstError`、`SkipContinuesOnlySafeBatch`:未勾後續0calls;勾選一般class11–16、前後交易0/XactState0、same DB、無LOB pending、log flush成功才下一批。任何 SqlError 嚴重/timeout/傳輸/不明 outcome 不可 skip,不比對 message 語言。 +- [ ] **Step 2: 實作預檢→確認→執行流程。** 所有 input encoding/batch/native/目標/log 可寫性問題於第一個 DB write 前阻擋,parser失敗時execution factory calls=0;不同檔案/target/skip設定令預檢失效,ReusedPreflightIsRejected 測試第二次 Run 不送 SQL。一次一批,結果與 state 查明後才確認 bytes;目前batch可能部分生效,分開成功、失敗與未知批次。 +- [ ] **Step 3: 實作 native batch role/state gate 及 EOF。** native LOB initialization/assemble/commit 任一 error fatal,即使 XACT_STATE0;普通batch遇錯也查已初始化 native state。每個走到 EOF 的作業都查交易、identity、digest、LOB唯一state/Failed0/Consumed1/Sequence=ConsumedThrough,包含 skip/DataOnly;pending/missing/wrongjob 不得 amber完成。無錯 NativeSchema 才逐表 COUNT_BIG 對 footer tables/rows,核對可取消。 +- [ ] **Step 4: 實作取消/cleanup terminal tests。** 先 Stopping、不排下一批;Cancel10秒無回應只關本 session;cleanup10秒限時。自然 EOF 未結交易、取消在成功回應邊界、狀態查詢/COUNT_BIG/log flush 中取消、cleanup未確認都測。已失敗的原始結果不能被 cleanup exception 覆蓋;若最後 log失敗要顯示存檔未完整。 +- [ ] **Step 5: 跑 worker filter、提交。** `PartialBatchEffectsAreNotReportedAsRows`、`SkippedRunStillChecksEofState`、`NativeLobPendingAtEofFails`、`NoReconnectOrReplay` 均通過。Commit `feat: execute MSSQL import batches with explicit outcomes`。 + +## Task 5: Four-step native wizard、Punky 與 MSSQL routing + +**Files:** Create `mySQLPunk/MssqlImportWizardForm.cs`, `mySQLPunk/Form1.MssqlImport.cs`, `tests/SmokeTests.MssqlImport.Wizard.cs`;Modify Form1.cs 的 ImportSqlWithDialog、csproj/smoke source registrations;只必要時局部擴充既有 theme helper。 + +**Interfaces:** `MssqlImportWizardForm(MssqlImportRequest initialRequest, Func serviceFactory)`;Form1 `OpenMssqlImportWizard(TreeDatabaseTarget)`。沿用 PunkyReportLoadingControl.BeginExport/EndExport/SetRunning/Muted;routing 測試可注入 wizard runner,不需真連線。 + +- [ ] **Step 1: 先寫失敗 wizard tests。** 四步導覽、未預檢/有阻擋不能開始、確認target必勾、skip預設false;重選檔案/目標會失效舊預檢;關閉釋放 input。所有檔案入口在 MSSQL 先路由新 wizard,其他引擎與查詢編輯器維持既有呼叫。 +- [ ] **Step 2: 實作符合核准原型的 WinForms layout。** 顯示實際 server/db、檔案size/編碼/native摘要、READ COMMITTED警告、一般腳本intrinsics邊界與部分寫入說明;結果明示實際核對範圍。log textarea ReadOnly,最近100/64KiB與總數/fullpath,open/folder/copy操作真實檔案。 +- [ ] **Step 3: 接 background worker 與單一 cancellation owner。** jobId+generation 擋 late callback;timer約200ms拉取bounded snapshot;忙碌時不重入、FormClosing轉取消,收尾後才關窗;Disposed UI 不被 callback更新。Punky預設loop、first-cycle音效/靜音、無播放/暫停按鈕。 +- [ ] **Step 4: 執行 native UI tests。** STA+WindowsFormsSynchronizationContext、form.Show/PerformClick/bounded DoEvents;深淺色、高 DPI、縮放後取消可到達、error截段、停止中與終態、close/complete race。若使用 preview,只新增 `MYSQLPUNK_MSSQL_IMPORT_WIZARD_PREVIEW/THEME` 且不開真DB,不能混用 export preview knob。 +- [ ] **Step 5: 跑 wizard filter及路由回歸、提交。** 把 native screenshots 存 `docs/design/mssql-import/snapshot/`,與原型JPEG分開命名;記錄動畫視覺/聲音哪些是實際人工確認。Commit `feat: add MSSQL SQL import wizard`。 + +## Task 6: Authorized isolated DB roundtrip 與 fault acceptance + +**Files:** Complete `tests/SmokeTests.MssqlImport.Integration.cs`,Create `tests/Run-MssqlImportIntegration.ps1` 及必要小型 `tests/MssqlImportFixtures/` SQL;記錄 `docs/design/mssql-import/verification.md`。大型生成檔與 evidence 不進 Git。 + +**Interfaces:** runner 參數 `-Run -AuthorizationPath -Profile Core|Lob|Geometry|Faults|Memory|All -OutputDirectory `。授權必須解析成 `(localdb)\mySQLPunkExportTest_20261012`、明確C fixture root及owner token;沒有有效manifest不得寫DB。runner 設定並還原 `MYSQLPUNK_MSSQL_IMPORT_INTEGRATION/SERVER/OUTPUT/AUTH/PROFILE`,filter固定 `MSSQL import integration`,要求實際 profile receipt,不能把未啟用測試當 live pass。runner 不自動啟動不明instance;必要時由controller啟動先前已核准的專用名稱。 + +- [ ] **Step 1: 補 runner guard 失敗 tests,再實作授權/cleanup保護。** 無-Run/錯server/錯root/reparse/非空output/不足20GiB皆不寫;GUID資料庫與實體檔、owner.token+DB owner extended property雙重驗證才可清。Existing export runner缺manifest不可默默跳過;明確AuthorizationPath,必要時從已核准fixture重新建立可審查manifest,不擴張到Transfer。 +- [ ] **Step 2: Core profile。** 新建owned source/target,以現有 exporter產生SQL,再由新 importer本體還原;比對表/欄位/型別/identity/PK/indexes/FK trust/view/table與column extended properties。General腳本含GO、temp/SET/transaction、SELECT多result;無外部sqlcmd作SUT,獨立驗證可另行使用。 +- [ ] **Step 3: Lob/Geometry profiles。** 64MiB binary、18MiB Unicode、NULL/empty/XML/Geometry含SRID/Z/M/curves與invalid-but-storable;以串流rawbytes/hash及metadata驗證。native DataOnly也測;注入missing/duplicate/reordered/replayed chunk、Failed1但交易0、missingstate、pendingEOF及final INSERT constraint/Deserialize失敗,即使skip也停止且下一row不寫。 +- [ ] **Step 4: Faults/Memory profiles。** 一般batch先INSERT再失敗的stop/skip;所有SqlError落檔;XACT_ABORT/未結交易/斷線/有限timeout seam/logcreate-append-flush-end失敗;取消在resultdrain/stateprobe/COUNT_BIG/close race。結果集數百萬列與64MiB回傳LOB應bounded drain。相同batchshape生成256MiB與2.5GiB串流檔,記錄x64/peak private bytes/working set;暖機後10倍檔案不能線性10倍成長,差異超過256MiB須調查並修復,不能只增加記憶體上限。 +- [ ] **Step 5: 各profile通過後提交tests及verification摘要。** 記錄命令、實際matched tests、SQL版本、耗時/artifactsize/hash/cleanup/memory/取消結果;失敗不寫pass,無法驗證明列邊界。Commit `test: verify native MSSQL import roundtrips and failures`。 + +## Task 7: SQL2019 Transfer 實檔試跑、整體驗證與交付 + +**Files:** Create `tests/Run-MssqlImportTransferTrial.ps1`, `docs/MSSQL_SQL_IMPORT.md`;Update verification.md、既有README適當入口/history(ignored)及plan完成狀態。產品修正僅限實際驗收發現的問題並覆核。 + +**Interfaces:** trial runner 必須明確 `-Run -Server localhost -Database Transfer -InputFile C:\Users\johnho\Desktop\Transfer_dump_20261013_165730.sql -OutputDirectory `;Windows整合登入,實際server必須`JOHN\MSSQL2019`、version15.x、compat150、ONLINE/READ_WRITE且NativeSchema空庫。無fixture drop/cleanup/recovery設定入口。runner 設定並還原 `MYSQLPUNK_MSSQL_IMPORT_TRIAL/SERVER/DATABASE/INPUT/OUTPUT`,由 Integration partial 中註冊的 `MssqlImportTransferTrial` 執行,filter `MSSQL import Transfer trial`;沒有 trial opt-in 時明確 skipped,-Run 時必須驗證真正執行 receipt,不能以 skipped 當驗收。 + +- [ ] **Step 1: 先測trial guard再唯讀重查。** 目標已非空、身份/DB create_date變化、檔案不符、空間不足或權限不足時只呈現實際狀態,不能自動清庫、換帳號或重試。記錄source完整預掃描/SHA、batch數/最大batch;不要複製或公開服務這份4.17GiB檔案。 +- [ ] **Step 2: 依使用者已有授權執行一次本機實檔。** default-stop,log與監測在C;記錄耗時、CPU/peakmemory、DBdata/log成長、最後位置、實際完成數/錯誤;READCOMMITTED來源的FK失敗不得改NOCHECK。失敗部分保留,先回報具體狀態,額外清除/重跑需使用者針對該狀態授權。 +- [ ] **Step 3: 核對結果。** 126 tables/3,247,785 rows為檔案footer預期,COUNT_BIG與實際objects/indexes/constraints/views/comments狀態獨立記錄;不把job完成當資料落地、不把count相同當逐欄hash相同。使用者未人工確認的聲音與操作體驗列pending。 +- [ ] **Step 4: 跑最終建置與既有回歸。** 清除本task filter後 `powershell.exe -NoProfile -File tests/Run-SmokeTests.ps1 -Configuration Release`;`./build.bat debug`、`./build.bat release`;AutoReleasePolicy通過。僅在新修正/失敗才重跑相關profiles;不反覆無理由全量還原。全分支一次fresh reviewer,再對實質fix做一次scoped覆核。 +- [ ] **Step 5: 文件、歷程與分支checkpoint。** docs說明支援GO/encoding/32MiB batch與LOB無關、generic intrinsics限制、skip/partial effects/logs/取消/ETA/需信任來源;列實際本機證據與未驗證production邊界。保留隔離worktree,精確stage,未獲本次授權前不push/merge/release。Commit `docs: document MSSQL SQL import and acceptance evidence`。 + +## Commands and execution setup + +實作開始時使用 `using-git-worktrees` 檢查已有隔離環境,再優先使用 Codex managed worktree,ref須包含本計畫checkpoint;不可從較舊remote branch遺漏已核准設計。不覆寫primary checkout的untracked檔。D槽空間偏低,managed worktree/生成fixture/build暫存優先C槽,先核對實際容量。 + +本專案新source與test partial都要登錄explicit清單。測試需匹配至少一項,filter沒匹配退出2不得當成功;第一次失敗退出1。測試命令範例(執行owner須保存並還原既有環境值): + +```powershell +$env:MYSQLPUNK_SMOKE_FILTER = 'MSSQL import parser' # 或 worker/wizard +powershell.exe -NoProfile -File tests/Run-SmokeTests.ps1 -Configuration Debug +Remove-Item Env:MYSQLPUNK_SMOKE_FILTER +powershell.exe -NoProfile -File tests/Run-SmokeTests.ps1 -Configuration Release +.\build.bat debug +.\build.bat release +``` + +每task依序記錄BASE/實作commit/測試證據/diff package/覆核結論。只修正實質spec或correctness問題,不做無意義review循環;user/production資料不拿來做破壞式fixture。計畫確認後沿用分工逐項覆核方式,不再重問執行方法。 From 0167e08f7eb35a59c74cb89524eabfe9e0825434 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 21:20:05 +0800 Subject: [PATCH 03/26] docs: start authorized MSSQL import execution --- docs/design/mssql-import/design.md | 4 +++- docs/design/mssql-import/implementation-plan.md | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/design/mssql-import/design.md b/docs/design/mssql-import/design.md index 5bb79cb..ff2e290 100644 --- a/docs/design/mssql-import/design.md +++ b/docs/design/mssql-import/design.md @@ -2,7 +2,7 @@ 日期:2026-10-13 基底:master,d45c903(已合併 MSSQL 匯出修正) -狀態:使用者於 2026-10-13 回覆「好,進實作」核准本規格;[書面實作計畫](implementation-plan.md) 已整理,尚未修改 importer 產品程式或執行 DB 匯入。 +狀態:使用者於 2026-10-13 回覆「好,進實作」核准本規格;[書面實作計畫](implementation-plan.md) 已整理並依明確進實作授權開始分工開發;實際 DB 匯入仍待驗收階段。 ## 1. 需求與本次範圍 @@ -74,6 +74,8 @@ v1 不接受獨立 T-SQL `USE` 切換至其他資料庫;lexer 能辨識這類 保留批次原文、順序及 session 的 SET、IDENTITY_INSERT、temp table、LOB staging 狀態。不中途插入全檔外層 transaction,也不改寫腳本自己的 transaction;允許一般腳本的交易跨 GO,但這種情況遇錯不能套用自動略過。 +批次間為確認交易與目標而插入的狀態查詢可能改變 @@ROWCOUNT/@@ERROR;v1 不保證這兩個 statement intrinsics 跨 GO 保持原值,一般腳本預檢與文件需明示。需要保留時應在同一 batch 先自行存入變數/temp table;既有 exporter 腳本不依賴這兩值跨 GO。此相容邊界於實作計畫與覆核裁決中固定,並以測試驗證。 + 成功回應只代表這個 batch 已完成執行,不代表其中的交易已提交;失敗/取消批次也可能已部分寫入。先前已提交的變更不會因取消整份還原。自然 EOF 尚有未結交易時不能顯示成功;停止後嘗試回復本次專用 session 的未提交交易並釋放連線,回復失敗或結果不明須記錄。 ## 5. 順序執行、大欄位與錯誤政策 diff --git a/docs/design/mssql-import/implementation-plan.md b/docs/design/mssql-import/implementation-plan.md index 858da04..4dd266a 100644 --- a/docs/design/mssql-import/implementation-plan.md +++ b/docs/design/mssql-import/implementation-plan.md @@ -10,7 +10,7 @@ **Spec:** [design.md](design.md),使用者於 2026-10-13 回覆「好,進實作」核准書面規格。 -**Status:** 書面實作計畫已整理,供最後範圍與步驟確認;尚未修改 importer 產品程式或執行 DB 匯入。 +**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 準備中。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 **Execution:** 保留先前選定的「分工實作並逐項覆核」。一次一位 implementer,各 task 經獨立覆核後才接下一項;最後整體覆核。build、native UI 與 DB tests 由單一 owner 串行執行,避免共享輸出/fixture 衝突。 @@ -62,7 +62,7 @@ - `MssqlImportInputException : Exception`:固定 `string Code` 與 `long BatchNumber/Line/ByteOffset`,讓預掃描失敗有穩定診斷。 - `MssqlImportScan`:`long FileBytes/BatchCount/MaxBatchCodeUnits`、`string EncodingName/Sha256`、`MssqlImportScriptInfo Script`;不保存所有批次。 - `MssqlImportScriptInfo`:`Kind { Generic, NativeSchema, NativeData }`、`Guid? NativeJobId`、`long? ExpectedTables/ExpectedRows`、`string SourceReadMode`、`bool HasLobProtocol`;native marker 候選毀損是預檢失敗,不降級 generic。 -- `MssqlImportInput.Open(string path): MssqlImportInput`;`Scan(CancellationToken, Action): MssqlImportScan`;`ReadBatches(CancellationToken): IEnumerable`;執行第二輪可取得 `ExecutionSha256`,物件為 IDisposable 並持有同一 handle。 +- `MssqlImportInput.Open(string path, string databaseName = null): MssqlImportInput`;`Scan(CancellationToken, Action): MssqlImportScan`;`ReadBatches(CancellationToken): IEnumerable`;執行第二輪可取得 `ExecutionSha256`,物件為 IDisposable 並持有同一 handle。 - `MssqlImportSqlError`:`int Number/State/Class/RelativeLine`、`string Message`;`MssqlImportBatchException` 保留本批全部 `IReadOnlyList Errors` 及 `bool OutcomeUncertain`,原始 exception 不送 UI。 - `MssqlImportSessionState`:`bool IsOpen`、`int DatabaseId/TransactionCount/XactState`;target identity 另含實際 ServerName/DatabaseName/DatabaseId/DatabaseCreateDate/Version/Writable/metadata 可見性/user object count。 - `MssqlImportLobState`:`bool Exists`、`long RowCount/Sequence/ConsumedThrough`、`bool Consumed/Failed`;native identifier 僅能由驗證過的 GUID 產生。 @@ -88,7 +88,7 @@ - [ ] **Step 1: 加入並跑失敗的 parser tests。** `MssqlImportParserPreservesContexts` 驗證字串/雙引號/方括號/巢狀 comment 中 GO 不拆;1/2/3/7-byte buffer 切在 UTF-8、BOM、CRLF、`''`、`]]` 中間仍原文相同。`MssqlImportParserLimits` 的斷言:16,777,216 code unit 的 Scan 成功且 MaxBatchCodeUnits 相等;16,777,217 時拋 MssqlImportInputException、Code="BatchTooLarge"。 - [ ] **Step 2: 實作固定 byte/decoder buffer、bounded current batch 與 lexical line candidate。** 不用無界 ReadLine、ReadAllText/ReadAllBytes/ReadToEnd;strict decoder 的 EOF flush 要抓無效序列。明訂 EndByte 包含目前 batch 的 GO delimiter,但 SQL Text 不含 GO。純註解/空白尾段不送空 command,其 byte 覆蓋只在 EOF 驗證通過後才計入最終 ProcessedBytes=FileBytes。 -- [ ] **Step 3: 補 unsupported/native tests 並實作 inspector。** GO n、GO block comment、SQLCMD 真指令、跨庫直接 USE、未閉合 EOF、無效 encoding 拒絕;字串中的相同文字不拒絕。同 DB USE 可接受。native Schema/DataOnly/無 LOB、正確/缺失/重複/溢位 footer、錯 job、偽造 GUID、header 不一致都要測;native candidate 不可因缺 footer 轉 generic。合法 Generic 不要求 footer。 +- [ ] **Step 3: 補 unsupported/native tests 並實作 inspector。** GO n、GO block comment、SQLCMD 真指令、跨庫直接 USE、未閉合 EOF、無效 encoding 拒絕;字串中的相同文字不拒絕。同 DB USE 在傳入 databaseName 且 decoded identifier 完全 Ordinal 相等時可接受;unknown target 或不同大小寫也保守拒絕,避免 case-sensitive server 的跨庫同批寫入。native Schema/DataOnly/無 LOB、正確/缺失/重複/溢位 footer、錯 job、偽造 GUID、header 不一致都要測;native candidate 不可因缺 footer 轉 generic。合法 Generic 不要求 footer。 - [ ] **Step 4: 以同一 handle 掃描→rewind→執行第二輪,測 SHA 一致與 FileShare.Read 阻止一般寫入/刪除;檔案重選 Dispose 後可寫。** 原始 byte/line offset、無 GO 的最後批次、僅註解檔不產生可執行空 command;大檔統計使用 Int64。 - [ ] **Step 5: 驗證並提交精確檔案。** `MYSQLPUNK_SMOKE_FILTER='MSSQL import parser'` 跑 `tests/Run-SmokeTests.ps1 -Configuration Debug`,必須 matched tests 全過;`git diff --check` 通過。Commit `feat: add bounded MSSQL GO input preflight`。 @@ -179,4 +179,4 @@ powershell.exe -NoProfile -File tests/Run-SmokeTests.ps1 -Configuration Release .\build.bat release ``` -每task依序記錄BASE/實作commit/測試證據/diff package/覆核結論。只修正實質spec或correctness問題,不做無意義review循環;user/production資料不拿來做破壞式fixture。計畫確認後沿用分工逐項覆核方式,不再重問執行方法。 +每task依序記錄BASE/實作commit/測試證據/diff package/覆核結論。只修正實質spec或correctness問題,不做無意義review循環;user/production資料不拿來做破壞式fixture。依使用者明確進實作的授權,沿用分工逐項覆核方式,不再重問執行授權或方法。 From 09825484883358801a9a7e8ae2aa596f8a7cc6e5 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 21:35:22 +0800 Subject: [PATCH 04/26] feat: add bounded MSSQL GO input preflight --- .../lib/MssqlImport/MssqlGoBatchReader.cs | 234 ++++++++++++++++++ mySQLPunk/lib/MssqlImport/MssqlImportInput.cs | 58 +++++ .../lib/MssqlImport/MssqlImportModels.cs | 54 ++++ .../MssqlImport/MssqlImportScriptInspector.cs | 209 ++++++++++++++++ mySQLPunk/mySQLPunk.csproj | 4 + tests/Run-SmokeTests.ps1 | 2 +- tests/SmokeTests.MssqlImport.Parser.cs | 175 +++++++++++++ tests/SmokeTests.cs | 5 + 8 files changed, 740 insertions(+), 1 deletion(-) create mode 100644 mySQLPunk/lib/MssqlImport/MssqlGoBatchReader.cs create mode 100644 mySQLPunk/lib/MssqlImport/MssqlImportInput.cs create mode 100644 mySQLPunk/lib/MssqlImport/MssqlImportModels.cs create mode 100644 mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs create mode 100644 tests/SmokeTests.MssqlImport.Parser.cs diff --git a/mySQLPunk/lib/MssqlImport/MssqlGoBatchReader.cs b/mySQLPunk/lib/MssqlImport/MssqlGoBatchReader.cs new file mode 100644 index 0000000..7679d96 --- /dev/null +++ b/mySQLPunk/lib/MssqlImport/MssqlGoBatchReader.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Threading; + +namespace mySQLPunk.lib.MssqlImport +{ + // A single bounded SQL buffer. The line candidate is a finite-state machine: + // a GO comment (including an arbitrarily long one) is never buffered. + internal sealed class MssqlGoBatchReader : IDisposable + { + internal const int MaxBatchCodeUnits = 16777216; + private enum Candidate { Leading, G, Go, Space, Dash, Comment, Sql } + private enum Context { Normal, Single, Double, Bracket, LineComment, BlockComment } + private readonly Stream stream; + private readonly int bufferSize; + private readonly Action progress; + private readonly Action observe; + private Context context; + private int blockDepth; + private bool skipPair, hasSql, reading; + private long number = 1, line = 1, byteOffset; + internal string EncodingName { get; private set; } + internal string Sha256 { get; private set; } + internal MssqlGoBatchReader(Stream stream, int bufferSize = 8192, Action progress = null, Action observe = null) + { + this.stream = stream ?? throw new ArgumentNullException(nameof(stream)); + if (bufferSize < 1 || bufferSize > 1048576) throw new ArgumentOutOfRangeException(nameof(bufferSize)); + this.bufferSize = bufferSize; this.progress = progress; this.observe = observe; + } + + internal IEnumerable ReadBatches(CancellationToken cancellation) + { + if (reading) throw new InvalidOperationException("Reader is single use."); + reading = true; + var sql = new StringBuilder(); + long startByte = 0, startLine = 1, endLine = 1; + int lineStart = 0; + bool overflow = false; + Candidate candidate = Candidate.Leading; + using (var chars = Decode(cancellation).GetEnumerator()) + { + bool more = chars.MoveNext(); + Unit current = more ? chars.Current : default(Unit); + while (more) + { + cancellation.ThrowIfCancellationRequested(); + more = chars.MoveNext(); + Unit next = more ? chars.Current : default(Unit); + char c = current.Character; + byteOffset = current.Start; + if (c == '\0') throw Error("EmbeddedNul"); + if (c == '\r' || c == '\n') + { + string newline = c.ToString(); + long boundary = current.End; + if (c == '\r' && more && next.Character == '\n') + { + newline = "\r\n"; boundary = next.End; + more = chars.MoveNext(); next = more ? chars.Current : default(Unit); + } + if (IsGo(candidate)) + { + sql.Length = lineStart; + var batch = new MssqlImportBatch(number, startByte, boundary, startLine, Math.Max(startLine, line - 1), sql.ToString(), EncodingName); + if (sql.Length != 0) observe?.Invoke(batch); + if (hasSql) { number++; yield return batch; } + sql.Clear(); hasSql = false; startByte = boundary; startLine = line + 1; + } + else + { + if (candidate == Candidate.Dash) throw Error("UnsupportedGo"); + if (overflow) throw Error("BatchTooLarge"); + Append(sql, newline); + if (context == Context.LineComment) context = Context.Normal; + skipPair = false; + endLine = line; + } + line++; lineStart = sql.Length; overflow = false; + candidate = context == Context.Normal ? Candidate.Leading : Candidate.Sql; + current = next; + continue; + } + + if (candidate != Candidate.Sql) + { + Candidate before = candidate; + candidate = Advance(candidate, c); + if (candidate == Candidate.Sql) + { + if (overflow) throw Error("BatchTooLarge"); + // The deferred prefix contains only whitespace/G/O, so has no + // lexical side effects. G/O become SQL if this isn't a GO line. + if (before != Candidate.Leading) hasSql = true; + Append(sql, c); Lex(c, more ? next.Character : '\0'); + } + else if (candidate != Candidate.Comment) + { + if (sql.Length < MaxBatchCodeUnits) sql.Append(c); else overflow = true; + } + } + else { Append(sql, c); Lex(c, more ? next.Character : '\0'); } + endLine = line; + current = next; + } + } + if (IsGo(candidate)) + { + sql.Length = lineStart; + var batch = new MssqlImportBatch(number, startByte, stream.Position, startLine, Math.Max(startLine, line - 1), sql.ToString(), EncodingName); + if (sql.Length != 0) observe?.Invoke(batch); + if (hasSql) yield return batch; + } + else + { + if (candidate == Candidate.Dash) throw Error("UnsupportedGo"); + if (overflow) throw Error("BatchTooLarge"); + if (context != Context.Normal && context != Context.LineComment) throw Error("UnclosedContext"); + var batch = new MssqlImportBatch(number, startByte, stream.Position, startLine, endLine, sql.ToString(), EncodingName); + if (sql.Length != 0) observe?.Invoke(batch); + if (hasSql) yield return batch; + } + } + + private Candidate Advance(Candidate state, char c) + { + if (state == Candidate.Comment) return state; + if (state == Candidate.Leading) return char.IsWhiteSpace(c) ? state : c == 'g' || c == 'G' ? Candidate.G : Candidate.Sql; + if (state == Candidate.G) return c == 'o' || c == 'O' ? Candidate.Go : Candidate.Sql; + if (state == Candidate.Go && (char.IsLetterOrDigit(c) || c == '_' || c == '#' || c == '@' || c == '$')) return Candidate.Sql; + if (state == Candidate.Dash) + { + if (c == '-') return Candidate.Comment; + throw Error("UnsupportedGo"); + } + if (char.IsWhiteSpace(c)) return Candidate.Space; + if (c == '-') return Candidate.Dash; + throw Error("UnsupportedGo"); + } + private static bool IsGo(Candidate candidate) => candidate == Candidate.Go || candidate == Candidate.Space || candidate == Candidate.Comment; + private void Append(StringBuilder sql, char c) { if (sql.Length == MaxBatchCodeUnits) throw Error("BatchTooLarge"); sql.Append(c); } + private void Append(StringBuilder sql, string text) { if ((long)sql.Length + text.Length > MaxBatchCodeUnits) throw Error("BatchTooLarge"); sql.Append(text); } + private MssqlImportInputException Error(string code, Exception inner = null) => new MssqlImportInputException(code, number, line, byteOffset, inner); + private void Lex(char c, char next) + { + if (skipPair) { skipPair = false; return; } + if (context == Context.LineComment) return; + if (context == Context.BlockComment) + { + if (c == '/' && next == '*') { blockDepth++; skipPair = true; } + else if (c == '*' && next == '/') { if (--blockDepth == 0) context = Context.Normal; skipPair = true; } + return; + } + if (context == Context.Single || context == Context.Double || context == Context.Bracket) + { + char close = context == Context.Single ? '\'' : context == Context.Double ? '"' : ']'; + if (c == close) { if (next == close) skipPair = true; else context = Context.Normal; } + return; + } + if (c == '-' && next == '-') { context = Context.LineComment; skipPair = true; } + else if (c == '/' && next == '*') { context = Context.BlockComment; blockDepth = 1; skipPair = true; } + else if (c == '\'') { context = Context.Single; hasSql = true; } + else if (c == '"') { context = Context.Double; hasSql = true; } + else if (c == '[') { context = Context.Bracket; hasSql = true; } + else if (!char.IsWhiteSpace(c)) hasSql = true; + } + + private struct Unit + { + internal char Character; + internal long Start, End; + internal Unit(char character, long start, long end) { Character = character; Start = start; End = end; } + } + private IEnumerable Decode(CancellationToken cancellation) + { + var prefix = new byte[4]; + int prefixCount = 0; + while (prefixCount < prefix.Length) + { + cancellation.ThrowIfCancellationRequested(); + int n = stream.Read(prefix, prefixCount, Math.Min(bufferSize, prefix.Length - prefixCount)); + if (n == 0) break; + prefixCount += n; + } + int bom = 0; + Encoding encoding = new UTF8Encoding(false, true); + if (prefixCount >= 4 && ((prefix[0] == 0xff && prefix[1] == 0xfe && prefix[2] == 0 && prefix[3] == 0) || (prefix[0] == 0 && prefix[1] == 0 && prefix[2] == 0xfe && prefix[3] == 0xff))) throw Error("InvalidEncoding"); + if (prefixCount >= 3 && prefix[0] == 0xef && prefix[1] == 0xbb && prefix[2] == 0xbf) bom = 3; + else if (prefixCount >= 2 && prefix[0] == 0xff && prefix[1] == 0xfe) { encoding = new UnicodeEncoding(false, true, true); bom = 2; } + else if (prefixCount >= 2 && prefix[0] == 0xfe && prefix[1] == 0xff) { encoding = new UnicodeEncoding(true, true, true); bom = 2; } + EncodingName = encoding.CodePage == 65001 ? (bom == 0 ? "UTF-8" : "UTF-8 BOM") : encoding.CodePage == 1200 ? "UTF-16 LE BOM" : "UTF-16 BE BOM"; + Decoder decoder = encoding.GetDecoder(); + var buffer = new byte[bufferSize]; + var decoded = new char[Math.Max(4, bufferSize + 2)]; + long decodedByte = bom, chunkStart = bom; + using (var hash = SHA256.Create()) + { + hash.TransformBlock(prefix, 0, prefixCount, null, 0); + byte[] source = prefix; int offset = bom, count = prefixCount - bom; + bool eof = false; + while (true) + { + cancellation.ThrowIfCancellationRequested(); + int usedBytes, usedChars; bool complete; + try { decoder.Convert(source, offset, count, decoded, 0, decoded.Length, eof, out usedBytes, out usedChars, out complete); } + catch (DecoderFallbackException ex) { byteOffset = Math.Max(0, chunkStart + ex.Index); throw Error("InvalidEncoding", ex); } + for (int i = 0; i < usedChars; i++) + { + char c = decoded[i]; + int bytes = encoding.CodePage != 65001 ? 2 : char.IsHighSurrogate(c) ? 0 : char.IsLowSurrogate(c) ? 4 : c < 0x80 ? 1 : c < 0x800 ? 2 : 3; + yield return new Unit(c, decodedByte, decodedByte + bytes); decodedByte += bytes; + } + offset += usedBytes; count -= usedBytes; chunkStart += usedBytes; + if (count != 0) continue; + if (eof) + { + hash.TransformFinalBlock(new byte[0], 0, 0); + Sha256 = BitConverter.ToString(hash.Hash).Replace("-", "").ToLowerInvariant(); + progress?.Invoke(stream.Position); + yield break; + } + int read = stream.Read(buffer, 0, buffer.Length); + chunkStart = stream.Position - read; + if (read > 0) { hash.TransformBlock(buffer, 0, read, null, 0); progress?.Invoke(stream.Position); } + source = buffer; offset = 0; count = read; eof = read == 0; + } + } + } + // The caller owns the same file handle across scan and execution. + public void Dispose() { } + } +} diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportInput.cs b/mySQLPunk/lib/MssqlImport/MssqlImportInput.cs new file mode 100644 index 0000000..ff40c14 --- /dev/null +++ b/mySQLPunk/lib/MssqlImport/MssqlImportInput.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +namespace mySQLPunk.lib.MssqlImport +{ + internal sealed class MssqlImportInput : IDisposable + { + private readonly FileStream file; + private readonly string databaseName; + private bool disposed, active; + internal string ExecutionSha256 { get; private set; } + private MssqlImportInput(string path, string databaseName) + { + file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 8192, FileOptions.SequentialScan); + this.databaseName = databaseName; + } + internal static MssqlImportInput Open(string path, string databaseName = null) => new MssqlImportInput(path, databaseName); + internal MssqlImportScan Scan(CancellationToken cancellation, Action progress) + { + Enter(); + try + { + file.Position = 0; ExecutionSha256 = null; + var inspector = new MssqlImportScriptInspector(databaseName); + long count = 0, max = 0; + using (var reader = new MssqlGoBatchReader(file, 8192, progress, inspector.Observe)) + { + foreach (var batch in reader.ReadBatches(cancellation)) { count++; max = Math.Max(max, (long)batch.Text.Length); } + return new MssqlImportScan(file.Length, count, max, reader.EncodingName, reader.Sha256, inspector.Complete()); + } + } + finally { active = false; } + } + internal IEnumerable ReadBatches(CancellationToken cancellation) + { + Enter(); + try + { + file.Position = 0; ExecutionSha256 = null; + using (var reader = new MssqlGoBatchReader(file)) + { + foreach (var batch in reader.ReadBatches(cancellation)) yield return batch; + ExecutionSha256 = reader.Sha256; + } + } + finally { active = false; } + } + private void Enter() + { + if (disposed) throw new ObjectDisposedException(nameof(MssqlImportInput)); + if (active) throw new InvalidOperationException("Input already has an active reader."); + active = true; + } + public void Dispose() { if (disposed) return; disposed = true; file.Dispose(); } + } +} diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs b/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs new file mode 100644 index 0000000..3b2a320 --- /dev/null +++ b/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs @@ -0,0 +1,54 @@ +using System; + +namespace mySQLPunk.lib.MssqlImport +{ + internal enum MssqlImportScriptKind { Generic, NativeSchema, NativeData } + + internal sealed class MssqlImportBatch + { + public long Number { get; } + public long StartByte { get; } + public long EndByte { get; } + public long StartLine { get; } + public long EndLine { get; } + public string Text { get; } + internal string SourceEncodingName { get; } + internal MssqlImportBatch(long number, long startByte, long endByte, long startLine, long endLine, string text, string sourceEncodingName = "UTF-8") + { Number = number; StartByte = startByte; EndByte = endByte; StartLine = startLine; EndLine = endLine; Text = text; SourceEncodingName = sourceEncodingName; } + } + + internal sealed class MssqlImportInputException : Exception + { + public string Code { get; } + public long BatchNumber { get; } + public long Line { get; } + public long ByteOffset { get; } + internal MssqlImportInputException(string code, long batchNumber, long line, long byteOffset, Exception inner = null) + : base(code + (code == "EmbeddedNul" ? " (unsupported embedded NUL or possible BOM-less UTF-16)" : "") + " at batch " + batchNumber + ", line " + line + ", byte " + byteOffset + ".", inner) + { Code = code; BatchNumber = batchNumber; Line = line; ByteOffset = byteOffset; } + } + + internal sealed class MssqlImportScriptInfo + { + public MssqlImportScriptKind Kind { get; } + public Guid? NativeJobId { get; } + public long? ExpectedTables { get; } + public long? ExpectedRows { get; } + public string SourceReadMode { get; } + public bool HasLobProtocol { get; } + internal MssqlImportScriptInfo(MssqlImportScriptKind kind, Guid? job, long? tables, long? rows, string mode, bool lob) + { Kind = kind; NativeJobId = job; ExpectedTables = tables; ExpectedRows = rows; SourceReadMode = mode; HasLobProtocol = lob; } + } + + internal sealed class MssqlImportScan + { + public long FileBytes { get; } + public long BatchCount { get; } + public long MaxBatchCodeUnits { get; } + public string EncodingName { get; } + public string Sha256 { get; } + public MssqlImportScriptInfo Script { get; } + internal MssqlImportScan(long bytes, long batches, long max, string encoding, string sha256, MssqlImportScriptInfo script) + { FileBytes = bytes; BatchCount = batches; MaxBatchCodeUnits = max; EncodingName = encoding; Sha256 = sha256; Script = script; } + } +} diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs b/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs new file mode 100644 index 0000000..b120f6e --- /dev/null +++ b/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs @@ -0,0 +1,209 @@ +using System; +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +namespace mySQLPunk.lib.MssqlImport +{ + internal sealed class MssqlImportScriptInspector + { + private const string Header = "Source read mode:"; + private const string Hint = "Restore into an empty, compatible target selected by the caller; existing objects fail."; + private const string Footer = "mysqlpunk-export-complete"; + private readonly string databaseName; + private bool candidate, header, hint, footer, schema, data, lob, usePending; + private string mode, createKind; + private Guid? job, lobJob; + private long? tables, rows; + private MssqlImportBatch current; + private int currentIndex; + private bool complete; + internal MssqlImportScriptInspector(string databaseName = null) { this.databaseName = databaseName; } + + internal void Observe(MssqlImportBatch batch) + { + if (complete) throw new InvalidOperationException("Inspector is complete."); + current = batch ?? throw new ArgumentNullException(nameof(batch)); + string text = batch.Text; + bool lineHasCode = false; + int i = 0; + while (i < text.Length) + { + currentIndex = i; + char c = text[i]; + if (c == '\r' || c == '\n') { lineHasCode = false; i++; continue; } + if (char.IsWhiteSpace(c)) { i++; continue; } + if (c == '-' && i + 1 < text.Length && text[i + 1] == '-') + { + int start = i + 2, end = start; + while (end < text.Length && text[end] != '\r' && text[end] != '\n') end++; + // Only actual line comments can carry native markers. Capture at most + // 512 characters, never the whole comment or all batch metadata. + if (!lineHasCode) Comment(text, start, end); + i = end; continue; + } + if (c == '/' && i + 1 < text.Length && text[i + 1] == '*') + { + int depth = 1; i += 2; + while (i < text.Length && depth != 0) + { + if (text[i] == '\r' || text[i] == '\n') lineHasCode = false; + if (i + 1 < text.Length && text[i] == '/' && text[i + 1] == '*') { depth++; i += 2; } + else if (i + 1 < text.Length && text[i] == '*' && text[i + 1] == '/') { depth--; i += 2; } + else i++; + } + continue; + } + if ((!lineHasCode && (c == ':' || (c == '!' && i + 1 < text.Length && text[i + 1] == '!'))) || (c == '$' && i + 1 < text.Length && text[i + 1] == '(')) throw Error("SqlCmdUnsupported"); + if (footer) throw Error("NativeFormat"); // Footer is an EOF marker, not an in-band hint. + bool firstCode = !lineHasCode; + lineHasCode = true; + if (c == '\'') + { + if (usePending) throw Error("DatabaseChange"); + SkipQuoted(text, ref i, '\'', null); + continue; + } + if (c == '[' || c == '"') + { + var token = new StringBuilder(); + SkipQuoted(text, ref i, c == '[' ? ']' : '"', token); + Token(token.ToString(), true); + continue; + } + if (IsWord(c)) + { + int start = i; + while (i < text.Length && IsWord(text[i])) i++; + int length = i - start; + if (firstCode && length == 2 && string.Compare(text, start, "GO", 0, 2, StringComparison.OrdinalIgnoreCase) == 0) throw Error("UnsupportedGo"); + // Long identifiers are irrelevant unless they claim our reserved native + // namespace or are the pending USE target; do not allocate the token. + if (length > 512) + { + if (usePending) throw Error("DatabaseChange"); + if (text[start] == '#' && length >= 4 && string.Compare(text, start, "#mp_", 0, 4, StringComparison.OrdinalIgnoreCase) == 0) throw Error("NativeFormat"); + createKind = null; + } + else Token(text.Substring(start, length), false); + continue; + } + if (usePending) throw Error("DatabaseChange"); + createKind = null; + i++; + } + if (usePending) throw Error("DatabaseChange"); + // Keep only immutable source coordinates, not the previous SQL payload. + current = new MssqlImportBatch(batch.Number, batch.StartByte, batch.EndByte, batch.StartLine, batch.EndLine, string.Empty); + currentIndex = 0; + } + + private static bool IsWord(char c) => char.IsLetterOrDigit(c) || c == '_' || c == '#' || c == '@' || c == '$'; + private void SkipQuoted(string text, ref int i, char close, StringBuilder value) + { + i++; + while (i < text.Length) + { + char c = text[i++]; + if (c == close) + { + if (i < text.Length && text[i] == close) i++; + else return; + } + if (value != null) + { + if (value.Length == 512) + { + if (usePending) throw Error("DatabaseChange"); + value = null; + } + else value.Append(c); + } + } + } + private void Token(string token, bool quoted) + { + if (usePending) + { + usePending = false; + if (databaseName == null || !string.Equals(token, databaseName, StringComparison.Ordinal)) throw Error("DatabaseChange"); + createKind = null; + return; + } + if (!quoted && token.Equals("USE", StringComparison.OrdinalIgnoreCase)) { usePending = true; return; } + if (!quoted && token.StartsWith("#mp_", StringComparison.OrdinalIgnoreCase)) + { + candidate = true; lob = true; + Guid parsed; + if (token.Length != 38 || token[36] != '_' || (token[37] != 's' && token[37] != 'v' && token[37] != 'c') || !Guid.TryParseExact(token.Substring(4, 32), "N", out parsed) || parsed == Guid.Empty) throw Error("NativeFormat"); + if (lobJob.HasValue && lobJob != parsed) throw Error("NativeFormat"); + lobJob = parsed; + createKind = null; + return; + } + if (createKind == "object") + { + if (!token.StartsWith("#", StringComparison.Ordinal)) schema = true; + createKind = null; + } + else if (createKind == "create" && !quoted && (token.Equals("TABLE", StringComparison.OrdinalIgnoreCase) || token.Equals("VIEW", StringComparison.OrdinalIgnoreCase) || token.Equals("PROCEDURE", StringComparison.OrdinalIgnoreCase) || token.Equals("FUNCTION", StringComparison.OrdinalIgnoreCase))) createKind = "object"; + else createKind = !quoted && token.Equals("CREATE", StringComparison.OrdinalIgnoreCase) ? "create" : null; + if (!quoted && (token.Equals("INSERT", StringComparison.OrdinalIgnoreCase) || token.Equals("UPDATE", StringComparison.OrdinalIgnoreCase) || token.Equals("DELETE", StringComparison.OrdinalIgnoreCase))) data = true; + } + private void Comment(string text, int start, int end) + { + while (start < end && char.IsWhiteSpace(text[start])) start++; + int count = Math.Min(end - start, 512); + string comment = text.Substring(start, count).TrimEnd(); + bool isHeader = comment.StartsWith("Source read mode", StringComparison.OrdinalIgnoreCase); + bool isHint = comment.StartsWith("Restore into an empty, compatible target", StringComparison.OrdinalIgnoreCase); + bool isFooter = comment.StartsWith(Footer, StringComparison.OrdinalIgnoreCase); + if (!isHeader && !isHint && !isFooter) return; + candidate = true; + if (end - start > 512 || footer) throw Error("NativeFormat"); + if (isHeader) + { + if (header || schema || data || lob || !comment.StartsWith(Header, StringComparison.Ordinal)) throw Error("NativeFormat"); + header = true; mode = comment.Substring(Header.Length).Trim(); + if (mode != "READ COMMITTED" && mode != "SNAPSHOT" && mode != "Schema only (no data transaction)") throw Error("NativeFormat"); + } + else if (isHint) + { + if (hint || !header || schema || data || lob || comment != Hint) throw Error("NativeFormat"); + hint = true; + } + else + { + var match = Regex.Match(comment, @"\Amysqlpunk-export-complete job=([0-9a-fA-F]{32}) tables=([0-9]+) rows=([0-9]+)\z", RegexOptions.CultureInvariant); + Guid parsed; long tableCount, rowCount; + if (!match.Success || !Guid.TryParseExact(match.Groups[1].Value, "N", out parsed) || parsed == Guid.Empty || !long.TryParse(match.Groups[2].Value, NumberStyles.None, CultureInfo.InvariantCulture, out tableCount) || !long.TryParse(match.Groups[3].Value, NumberStyles.None, CultureInfo.InvariantCulture, out rowCount)) throw Error("NativeFormat"); + footer = true; job = parsed; tables = tableCount; rows = rowCount; + } + } + internal MssqlImportScriptInfo Complete() + { + if (complete) throw new InvalidOperationException("Inspector is complete."); + complete = true; + if (!candidate) return new MssqlImportScriptInfo(MssqlImportScriptKind.Generic, null, null, null, null, false); + if (!header || !footer || (hint && !schema && (tables != 0 || rows != 0)) || (schema && !hint) || (lobJob.HasValue && lobJob != job) || (mode == "Schema only (no data transaction)" && (!hint || data || lob || rows != 0))) throw Error("NativeFormat"); + return new MssqlImportScriptInfo(hint ? MssqlImportScriptKind.NativeSchema : MssqlImportScriptKind.NativeData, job, tables, rows, mode, lob); + } + private MssqlImportInputException Error(string code) + { + if (current == null) return new MssqlImportInputException(code, 1, 1, 0); + long errorLine = current.StartLine; + for (int i = 0; i < currentIndex; i++) if (current.Text[i] == '\n' || (current.Text[i] == '\r' && (i + 1 == current.Text.Length || current.Text[i + 1] != '\n'))) errorLine++; + // Reader supplies exact byte encoding for variable-width source diagnostics. + string name = current.SourceEncodingName; + long prefixBytes = 0; + for (int i = 0; i < currentIndex; i++) + { + char c = current.Text[i]; + prefixBytes += name.StartsWith("UTF-16", StringComparison.Ordinal) ? 2 : char.IsHighSurrogate(c) ? 0 : char.IsLowSurrogate(c) ? 4 : c < 128 ? 1 : c < 2048 ? 2 : 3; + } + long bom = current.StartByte == 0 ? (name == "UTF-8 BOM" ? 3 : name.StartsWith("UTF-16", StringComparison.Ordinal) ? 2 : 0) : 0; + long offset = current.StartByte + bom + prefixBytes; + return new MssqlImportInputException(code, current.Number, errorLine, offset); + } + } +} diff --git a/mySQLPunk/mySQLPunk.csproj b/mySQLPunk/mySQLPunk.csproj index 1c539b1..9a45284 100644 --- a/mySQLPunk/mySQLPunk.csproj +++ b/mySQLPunk/mySQLPunk.csproj @@ -364,6 +364,10 @@ + + + + diff --git a/tests/Run-SmokeTests.ps1 b/tests/Run-SmokeTests.ps1 index 5eea199..03be78b 100644 --- a/tests/Run-SmokeTests.ps1 +++ b/tests/Run-SmokeTests.ps1 @@ -143,7 +143,7 @@ if (!(Test-Path -LiteralPath $mysqlConnector)) { /r:System.Core.dll ` /r:System.IO.Compression.dll ` /r:System.IO.Compression.FileSystem.dll ` - $source $preferencesSource $schemaSyncSource $erModelSource (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Snapshot.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Schema.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.ViewReferences.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Properties.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Artifact.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Values.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Lob.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Routing.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.SnapshotIntegration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.CompatibilityIntegration.cs") + (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Parser.cs") $source $preferencesSource $schemaSyncSource $erModelSource (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Snapshot.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Schema.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.ViewReferences.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Properties.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Artifact.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Values.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Lob.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Routing.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.SnapshotIntegration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.CompatibilityIntegration.cs") if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/tests/SmokeTests.MssqlImport.Parser.cs b/tests/SmokeTests.MssqlImport.Parser.cs new file mode 100644 index 0000000..54838be --- /dev/null +++ b/tests/SmokeTests.MssqlImport.Parser.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using mySQLPunk.lib.MssqlImport; + +public static partial class SmokeTests +{ + // Breaks caught: GO split inside a lexical context, decoder boundary corruption, + // accepting over-budget SQL, native downgrade, read-ahead progress and handle replacement. + private static void MssqlImportParserPreservesContexts() + { + string first = "SELECT N'羽😀\r\nGO\r\n''x';\r\nSELECT \"a\"\"\r\nGO\r\nb\", [a]]\r\nGO\r\nb];\r\n/* outer\r\n/* nested */\r\nGO\r\n*/\r\n-- GO\r\n"; + string last = "SELECT 2;"; + foreach (Encoding encoding in new Encoding[] { new UTF8Encoding(false,true), new UTF8Encoding(true,true), new UnicodeEncoding(false,true,true), new UnicodeEncoding(true,true,true) }) + foreach (int buffer in new[] {1,2,3,7}) + { + byte[] bytes = ImportBytes(first + " gO -- end\r\n" + last, encoding); + using (var stream = new MemoryStream(bytes)) + using (var reader = new MssqlGoBatchReader(stream, buffer)) + { + var batches = reader.ReadBatches(CancellationToken.None).ToArray(); + Assert(batches.Length == 2, "Context-aware GO reader yields exactly two commands."); + Assert(batches[0].Text == first && batches[1].Text == last, "Original SQL text survives tiny decode buffers and quote escapes."); + Assert(batches[0].StartByte == 0 && batches[0].EndByte == ImportBytes(first + " gO -- end\r\n",encoding).LongLength, "EndByte includes original encoded GO line and BOM."); + Assert(batches[1].StartByte == batches[0].EndByte && batches[1].EndByte == bytes.LongLength, "Byte ranges cover last undelimited command."); + Assert(batches[0].StartLine == 1 && batches[0].EndLine == 13 && batches[1].StartLine == 15 && batches[1].EndLine == 15, "Original line offsets exclude GO delimiter."); + } + } + using(var input = ImportInput("-- only\r\n/* nested /* ok */ end */\r\nGO\r\n-- tail")) + { + Assert(input.Scan(CancellationToken.None,null).BatchCount==0, "Only comments never become executable commands."); + Assert(!input.ReadBatches(CancellationToken.None).Any() && input.ExecutionSha256!=null, "Comment-only EOF still finishes execution digest."); + } + } + + private static void MssqlImportParserLimits() + { + const int limit = 16777216; + string sql = "SELECT '" + new string('x',limit-10) + "';"; + Assert(sql.Length==limit, "Fixture reaches the documented code-unit boundary."); + using(var input=ImportInput(sql+"\r\nGO\r\n")) + { + // The CRLF preceding GO is SQL text and counts toward the batch budget. + ImportReject(input,"BatchTooLarge"); + } + using(var input=ImportInput(sql)) + { + var scan=input.Scan(CancellationToken.None,null); + Assert(scan.BatchCount==1 && scan.MaxBatchCodeUnits==limit,"Exactly 16,777,216 code units scan successfully."); + } + using(var input=ImportInput(sql+" ")) ImportReject(input,"BatchTooLarge"); + string framed = "SELECT '" + new string('x',limit-12) + "';\r\n"; + using(var input=ImportInput(framed+"GO --delimiter\r\n")) + Assert(input.Scan(CancellationToken.None,null).MaxBatchCodeUnits==limit,"Exact cap remains valid with a GO delimiter excluded from SQL."); + using(var input=ImportInput("SELECT 1;\n"+new string(' ',limit+5)+"GO --"+new string('x',limit+5)+"\nSELECT 2;")) + Assert(input.Scan(CancellationToken.None,null).BatchCount==2,"Oversized GO whitespace/comment candidates are discarded without losing commands."); + using(var input=ImportInput(new string(' ',limit+5)+"SELECT 1;")) ImportReject(input,"BatchTooLarge"); + using(var input=ImportInput("--"+new string(' ',limit-2))) + Assert(input.Scan(CancellationToken.None,null).BatchCount==0,"Huge single comment line is bounded without an empty command."); + } + + private static void MssqlImportParserUnsupported() + { + foreach(string sql in new[]{"SELECT 1\nGO 2\n","SELECT 1\nGO /*comment*/\n","SELECT 1\nGO--ok\n:r file.sql","/*ok*/ :setvar a b","!! whoami","SELECT 1; USE [other];","USE [transfer];"}) + using(var input=ImportInput(sql,"Transfer")) ImportReject(input,sql.Contains("GO 2")||sql.Contains("GO /*")?"UnsupportedGo":sql.Contains("USE")?"DatabaseChange":"SqlCmdUnsupported"); + using(var input=ImportInput("/* same-line comment */ GO\n")) ImportReject(input,"UnsupportedGo"); + foreach(string sql in new[]{"SELECT '\nGO","SELECT [abc","SELECT \"abc","/* /* nested */"}) + using(var input=ImportInput(sql)) ImportReject(input,"UnclosedContext"); + using(var input=ImportInput("USE [Tran]]sfer]; SELECT ':r file.sql GO 2 !!'; -- USE other\n","Tran]sfer")) + Assert(input.Scan(CancellationToken.None,null).BatchCount==1,"Exact decoded same-database USE succeeds; string/comment directives are inert."); + using(var input=ImportInput("USE \"Transfer\";", "Transfer")) Assert(input.Scan(CancellationToken.None,null).BatchCount==1,"Double-quoted exact USE succeeds."); + using(var input=ImportInput("USE Transfer;")) ImportReject(input,"DatabaseChange"); + foreach(Encoding encoding in new Encoding[]{new UTF8Encoding(true,true),new UnicodeEncoding(false,true,true),new UnicodeEncoding(true,true,true)}) + { + string prefix="SELECT N'\u7fbd\U0001f600';\r\n"; + using(var input=ImportInput(ImportBytes(prefix+"USE [other];",encoding),"Transfer")) + { + try {input.Scan(CancellationToken.None,null);Assert(false,"Cross-database USE must reject.");} + catch(MssqlImportInputException ex) {Assert(ex.Code=="DatabaseChange" && ex.Line==2 && ex.ByteOffset==ImportBytes(prefix+"USE ",encoding).LongLength,"Error source byte/line coordinates use original encoding and BOM.");} + } + } + foreach(byte[] bytes in new[]{new byte[]{0xef,0xbb},new byte[]{0xc0,0xaf},new byte[]{0xe2,0x82},new byte[]{0xff,0xfe,0x00},new byte[]{0xff,0xfe,0x00,0xd8},new byte[]{0xfe,0xff,0xdc,0x00},new byte[]{0xff,0xfe,0,0,0,0,0,0}}) + using(var input=ImportInput(bytes)) ImportReject(input,"InvalidEncoding"); + foreach(byte[] bytes in new[]{new byte[]{0x53,0,0x45,0},ImportBytes("SELECT '\0';",new UTF8Encoding(false,true)),ImportBytes("SELECT '\0';",new UnicodeEncoding(false,true,true))}) + using(var input=ImportInput(bytes)) ImportReject(input,"EmbeddedNul"); + using(var input=ImportInput("SELECT '$(name) :connect !!';")) Assert(input.Scan(CancellationToken.None,null).BatchCount==1,"No SQLCMD expansion in strings."); + } + + private const string ImportJob="123456781234123412341234567890ab"; + private const string ImportHeader="-- Source read mode: READ COMMITTED\r\n"; + private const string ImportHint="-- Restore into an empty, compatible target selected by the caller; existing objects fail.\r\n"; + private const string ImportFooter="-- mysqlpunk-export-complete job="+ImportJob+" tables=1 rows=2\r\n"; + private static void MssqlImportParserNative() + { + string schema=ImportHeader+ImportHint+"CREATE TABLE [dbo].[x] ([a] int);\r\nGO\r\n"+ImportFooter; + using(var input=ImportInput(schema)) + { + var script=input.Scan(CancellationToken.None,null).Script; + Assert(script.Kind==MssqlImportScriptKind.NativeSchema && script.NativeJobId==Guid.ParseExact(ImportJob,"N") && script.ExpectedTables==1 && script.ExpectedRows==2 && !script.HasLobProtocol && script.SourceReadMode=="READ COMMITTED","Native schema metadata is exact without requiring LOB."); + } + using(var input=ImportInput(ImportHeader+"INSERT INTO dbo.x VALUES(1);\r\nGO\r\n"+ImportFooter)) + Assert(input.Scan(CancellationToken.None,null).Script.Kind==MssqlImportScriptKind.NativeData,"Existing DataOnly header is accepted without a new mode manifest."); + using(var input=ImportInput(ImportHeader+"CREATE TABLE #mp_"+ImportJob+"_s ([Sequence] bigint);\r\nGO\r\n"+ImportFooter)) + Assert(input.Scan(CancellationToken.None,null).Script.HasLobProtocol,"Actual validated native temporary identifiers mark LOB."); + foreach(string sql in new[]{ImportHeader+ImportHint+"CREATE TABLE x(a int);",schema+ImportFooter,schema.Replace("rows=2","rows=9223372036854775808"),schema.Replace("tables=1","tables=-1"),schema.Replace(ImportJob,"bad"),ImportFooter,ImportHeader+"CREATE TABLE x(a int);\nGO\n"+ImportFooter,ImportHeader+ImportHeader+ImportFooter,ImportHeader.Replace("READ COMMITTED","unknown")+ImportFooter,ImportHeader+"CREATE TABLE #mp_ffffffffffffffffffffffffffffffff_s (a int);\nGO\n"+ImportFooter,ImportHeader+"CREATE TABLE #mp_bad_s (a int);\nGO\n"+ImportFooter,"CREATE TABLE #mp_"+ImportJob+"_s (a int);"}) + using(var input=ImportInput(sql)) ImportReject(input,"NativeFormat"); + using(var input=ImportInput("SELECT '-- Source read mode: READ COMMITTED', '-- mysqlpunk-export-complete job=bad', [#mp_bad_s];\nGO\n-- regular comment")) + Assert(input.Scan(CancellationToken.None,null).Script.Kind==MssqlImportScriptKind.Generic,"String/ordinary identifier decoys do not create native markers."); + using(var input=ImportInput("SELECT 1;\n")) Assert(input.Scan(CancellationToken.None,null).Script.Kind==MssqlImportScriptKind.Generic,"Generic SQL requires no native footer."); + using(var input=ImportInput("-- Source read mode READ COMMITTED\n")) ImportReject(input,"NativeFormat"); + string emptyFooter=ImportFooter.Replace("tables=1 rows=2","tables=0 rows=0"); + using(var input=ImportInput(ImportHeader+ImportHint+emptyFooter)) + Assert(input.Scan(CancellationToken.None,null).Script.Kind==MssqlImportScriptKind.NativeSchema,"Existing zero-object schema export remains valid."); + using(var input=ImportInput(ImportHeader.Replace("READ COMMITTED","Schema only (no data transaction)")+ImportHint+"CREATE TABLE x(a int);\nGO\n"+ImportFooter.Replace("rows=2","rows=0"))) + Assert(input.Scan(CancellationToken.None,null).Script.Kind==MssqlImportScriptKind.NativeSchema,"SchemaOnly source mode and zero row footer are coherent."); + foreach(string malformed in new[]{ImportHeader+ImportHint+"SELECT 'CREATE TABLE x(a int)';\nGO\n"+ImportFooter,"CREATE TABLE x(a int);\nGO\n"+ImportHeader+ImportHint+ImportFooter,ImportHeader.Replace("READ COMMITTED","Schema only (no data transaction)")+ImportHint+"CREATE TABLE x(a int); INSERT INTO x VALUES(1);\nGO\n"+ImportFooter}) + using(var input=ImportInput(malformed)) ImportReject(input,"NativeFormat"); + } + + private static void MssqlImportParserFileIdentity() + { + byte[] bytes=ImportBytes("SELECT N'羽😀';\r\nGO\r\n-- footer only\r\n",new UTF8Encoding(true,true)); + string path=ImportFixture(bytes); + try + { + using(var input=MssqlImportInput.Open(path)) + { + long progress=0; + var scan=input.Scan(CancellationToken.None,p=>{Assert(p>=progress&&p<=bytes.LongLength,"Scan progress is monotonic bytes.");progress=p;}); + string expected; + using(var hash=SHA256.Create()) expected=BitConverter.ToString(hash.ComputeHash(bytes)).Replace("-","").ToLowerInvariant(); + Assert(scan.Sha256==expected && scan.FileBytes==bytes.LongLength && progress==bytes.LongLength,"Preflight hashes all original bytes including BOM and comment tail."); + Assert(input.ExecutionSha256==null,"Scan cannot claim execution digest."); + var commands=input.ReadBatches(CancellationToken.None).ToArray(); + Assert(commands.Length==1 && commands[0].EndByte(()=>{using(var writer=new FileStream(path,FileMode.Open,FileAccess.Write,FileShare.ReadWrite)){}},"Held input blocks general writers."); + AssertThrows(()=>File.Delete(path),"Held input blocks delete."); + } + using(var writer=new FileStream(path,FileMode.Open,FileAccess.Write,FileShare.None)) writer.WriteByte(0x20); + } + finally {File.Delete(path);} + using(var input=ImportInput("SELECT 1;\nGO\nSELECT 2;")) + { + var cancel=new CancellationTokenSource();cancel.Cancel(); + AssertThrows(()=>input.Scan(cancel.Token,null),"Preflight cancellation performs no full scan."); + input.Scan(CancellationToken.None,null); + using(var enumerator=input.ReadBatches(CancellationToken.None).GetEnumerator()) {Assert(enumerator.MoveNext(),"First command exists.");} + Assert(input.ExecutionSha256==null,"Abandoned enumeration never claims EOF digest."); + } + } + + private static byte[] ImportBytes(string sql,Encoding encoding) {return encoding.GetPreamble().Concat(encoding.GetBytes(sql)).ToArray();} + private static string ImportFixture(byte[] bytes) {string path=Path.Combine(Path.GetTempPath(),"mysqlpunk-import-parser-"+Guid.NewGuid().ToString("N")+".sql");File.WriteAllBytes(path,bytes);return path;} + private static ImportParserFixture ImportInput(string sql,string database=null) {return ImportInput(new UTF8Encoding(false,true).GetBytes(sql),database);} + private static ImportParserFixture ImportInput(byte[] bytes,string database=null) {return new ImportParserFixture(bytes,database);} + private sealed class ImportParserFixture : IDisposable + { + private readonly string path; + private readonly MssqlImportInput input; + internal ImportParserFixture(byte[] bytes,string database) {path=ImportFixture(bytes);try {input=MssqlImportInput.Open(path,database);}catch {File.Delete(path);throw;}} + internal MssqlImportScan Scan(CancellationToken token,Action progress) {return input.Scan(token,progress);} + internal IEnumerable ReadBatches(CancellationToken token) {return input.ReadBatches(token);} + internal string ExecutionSha256 {get {return input.ExecutionSha256;}} + public void Dispose() {input.Dispose();File.Delete(path);} + } + private static void ImportReject(ImportParserFixture input,string code) + { + try {input.Scan(CancellationToken.None,null);Assert(false,"Expected preflight rejection: "+code);} + catch(MssqlImportInputException ex) {Assert(ex.Code==code,"Stable preflight code: expected "+code+", got "+ex.Code);Assert(ex.Line>=1&&ex.ByteOffset>=0&&ex.BatchNumber>=1,"Rejected input has source coordinates.");} + } +} diff --git a/tests/SmokeTests.cs b/tests/SmokeTests.cs index 7ab5ac4..456f8d4 100644 --- a/tests/SmokeTests.cs +++ b/tests/SmokeTests.cs @@ -31,6 +31,11 @@ public static int Main(string[] args) if (args.Length != 0) return SnapshotCrashChild(args); if (Environment.GetEnvironmentVariable("MYSQLPUNK_MSSQL_WIZARD_PREVIEW") == "1") return WizardPreview(); int passed = 0; + Run("MSSQL import parser contexts", MssqlImportParserPreservesContexts, ref passed); + Run("MSSQL import parser limits", MssqlImportParserLimits, ref passed); + Run("MSSQL import parser unsupported", MssqlImportParserUnsupported, ref passed); + Run("MSSQL import parser native", MssqlImportParserNative, ref passed); + Run("MSSQL import parser file identity", MssqlImportParserFileIdentity, ref passed); Run("MSSQL export restore process timeout evidence", RestoreProcess_TimeoutEvidence, ref passed); Run("MSSQL export snapshot worker late start unavailable", SnapshotWorker_LateStartUnavailable, ref passed); Run("MSSQL export snapshot worker start busy", SnapshotWorker_StartBusy, ref passed); From 9b21e4575af158b761a1c4e682a4eca785a2fc04 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 21:36:16 +0800 Subject: [PATCH 05/26] docs: define MSSQL SQL text encoding edge policy --- docs/design/mssql-import/design.md | 2 +- docs/design/mssql-import/implementation-plan.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/design/mssql-import/design.md b/docs/design/mssql-import/design.md index ff2e290..ce0b175 100644 --- a/docs/design/mssql-import/design.md +++ b/docs/design/mssql-import/design.md @@ -48,7 +48,7 @@ Punky 預設自動循環播放,不設播放或暫停按鈕;聲音僅首輪 採兩次順序讀取:先完整掃描取得總 bytes/批次數/最大批次/SHA-256/格式資訊,再 rewind 同一個 handle 執行。兩次都用固定 buffer,不保存所有 batch 或全部行號索引。更換檔案、目標或關鍵設定會使預檢失效;開始前再次讀取目標狀態。 -- v1 支援嚴格 UTF-8(有/無 BOM)及有 BOM 的 UTF-16 LE/BE;拒絕無法判定或有無效序列的編碼,不能以替代字元默默執行。來源檔案不改寫。 +- v1 支援嚴格 UTF-8(有/無 BOM)及有 BOM 的 UTF-16 LE/BE;拒絕無法判定或有無效序列的編碼,不能以替代字元默默執行。來源檔案不改寫。 解碼後的 U+0000 在 v1 SQL 文字中不支援,回報 EmbeddedNul;它可能來自沒有 BOM 的 UTF-16,也可能是合法 UTF-8 的 literal NUL,不誤稱必然是錯誤編碼。這是腳本文字相容邊界,既有 exporter 的資料值採 binary 表達,不新增欄位限制。 - GO 不分大小寫,須位於字串、quoted identifier、bracket identifier 與註解之外的獨立一行。支援前後空白及 `GO -- 註解`;GO 不送給 SQL Server。v1 不支援 GO 重複次數與同一分隔行的 block comment,預掃描發現這類 GO 語法時明確拒絕。 - lexer 跨 buffer 維持狀態,處理單引號/N 字串與 `''`、雙引號與 `""`、方括號與 `]]`、單行註解、巢狀 block comment、CRLF/LF 及多位元字元。字串/註解中的 GO 保留原文。行本身也不得以無上限 ReadLine 累積。 - EOF 的最後一個非空批次照常執行;未閉合的字串、identifier 或 block comment 在預掃描擋下。空批次不送出,不用分號拆解任意 T-SQL。 diff --git a/docs/design/mssql-import/implementation-plan.md b/docs/design/mssql-import/implementation-plan.md index 4dd266a..fd6f4ab 100644 --- a/docs/design/mssql-import/implementation-plan.md +++ b/docs/design/mssql-import/implementation-plan.md @@ -19,7 +19,7 @@ - 保留既有編碼/BOM/換行;不碰 unrelated `mySQLPunk.Desktop/Properties/`,不讀取帳號 token/瀏覽器 session/已存連線或登入設定。 - 只替換 MSSQL 的檔案執行入口;其他 DB 引擎及查詢編輯器不改,`IDatabase` 公開契約不擴張。 - 單一 GO 批次上限為解碼後 32 MiB,即 16,777,216 個 UTF-16 code unit;不是欄位大小上限。不能插 GO/依分號硬切。禁止整檔 bytes/string/AST/batch list。 -- 嚴格 UTF-8 有/無 BOM、UTF-16 LE/BE 有 BOM;保留原文及同一 session。支援獨立 GO/GO -- 註解,拒絕 GO n、同分隔行 block comment、SQLCMD 指令與跨 DB 的直接 USE。 +- 嚴格 UTF-8 有/無 BOM、UTF-16 LE/BE 有 BOM;解碼後 U+0000 回報 EmbeddedNul,明示 v1 literal-NUL 相容邊界,不能誤稱 UTF-8 NUL 一定是無效編碼;保留原文及同一 session。支援獨立 GO/GO -- 註解,拒絕 GO n、同分隔行 block comment、SQLCMD 指令與跨 DB 的直接 USE。 - 預設不略過錯誤;略過對象為失敗 GO batch,不是單筆 row。timeout/斷線/log IO/未知交易/native LOB 失敗仍停止,不重連、重試、重播或續傳。 - 專用連線明確指定 Initial Catalog;ConnectRetryCount=0,單一 command,CommandTimeout=0。狀態查詢 5 秒、cleanup 10 秒,取消 10 秒無回應後只嘗試關閉本次 owned connection。 - 不新增全檔外層 transaction、不自動清庫/DROP 使用者物件、不改 SNAPSHOT/recovery model/constraint trust、不 GRANT/KILL。 From 3ebf6b3146f1933112b1f7b4fc941f800975f029 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 21:47:31 +0800 Subject: [PATCH 06/26] fix: preserve import decoder coordinates and reject SQLCMD suffixes --- .../lib/MssqlImport/MssqlGoBatchReader.cs | 42 +++++++++++++++++-- .../MssqlImport/MssqlImportScriptInspector.cs | 6 ++- tests/SmokeTests.MssqlImport.Parser.cs | 27 ++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/mySQLPunk/lib/MssqlImport/MssqlGoBatchReader.cs b/mySQLPunk/lib/MssqlImport/MssqlGoBatchReader.cs index 7679d96..43fc317 100644 --- a/mySQLPunk/lib/MssqlImport/MssqlGoBatchReader.cs +++ b/mySQLPunk/lib/MssqlImport/MssqlGoBatchReader.cs @@ -47,6 +47,9 @@ internal IEnumerable ReadBatches(CancellationToken cancellatio while (more) { cancellation.ThrowIfCancellationRequested(); + // Decode failures are deferred through lookahead, so all preceding + // valid CR/LF and GO boundaries update the source coordinates first. + if (current.DecodeError != null) { byteOffset = current.Start; throw Error("InvalidEncoding", current.DecodeError); } more = chars.MoveNext(); Unit next = more ? chars.Current : default(Unit); char c = current.Character; @@ -171,7 +174,9 @@ private struct Unit { internal char Character; internal long Start, End; - internal Unit(char character, long start, long end) { Character = character; Start = start; End = end; } + internal DecoderFallbackException DecodeError; + internal Unit(char character, long start, long end) { Character = character; Start = start; End = end; DecodeError = null; } + internal Unit(long offset, DecoderFallbackException error) { Character = '\0'; Start = End = offset; DecodeError = error; } } private IEnumerable Decode(CancellationToken cancellation) { @@ -195,6 +200,7 @@ private IEnumerable Decode(CancellationToken cancellation) var buffer = new byte[bufferSize]; var decoded = new char[Math.Max(4, bufferSize + 2)]; long decodedByte = bom, chunkStart = bom; + int previousByte = -1; using (var hash = SHA256.Create()) { hash.TransformBlock(prefix, 0, prefixCount, null, 0); @@ -203,15 +209,26 @@ private IEnumerable Decode(CancellationToken cancellation) while (true) { cancellation.ThrowIfCancellationRequested(); - int usedBytes, usedChars; bool complete; - try { decoder.Convert(source, offset, count, decoded, 0, decoded.Length, eof, out usedBytes, out usedChars, out complete); } - catch (DecoderFallbackException ex) { byteOffset = Math.Max(0, chunkStart + ex.Index); throw Error("InvalidEncoding", ex); } + int usedBytes = 0, usedChars = 0; bool complete; + // Decode only through the next encoded newline. A failed conversion + // can then hide no earlier line/GO transition in its valid prefix. + // Reads and buffers stay fixed-size; this is not byte-at-a-time decoding. + int span = DecodeSpan(source, offset, count, chunkStart, bom, encoding.CodePage, previousByte); + DecoderFallbackException failure = null; + try { decoder.Convert(source, offset, span, decoded, 0, decoded.Length, eof, out usedBytes, out usedChars, out complete); } + catch (DecoderFallbackException ex) { failure = ex; } + if (failure != null) + { + yield return new Unit(Math.Max(0, chunkStart + failure.Index), failure); + yield break; + } for (int i = 0; i < usedChars; i++) { char c = decoded[i]; int bytes = encoding.CodePage != 65001 ? 2 : char.IsHighSurrogate(c) ? 0 : char.IsLowSurrogate(c) ? 4 : c < 0x80 ? 1 : c < 0x800 ? 2 : 3; yield return new Unit(c, decodedByte, decodedByte + bytes); decodedByte += bytes; } + if (usedBytes != 0) previousByte = source[offset + usedBytes - 1]; offset += usedBytes; count -= usedBytes; chunkStart += usedBytes; if (count != 0) continue; if (eof) @@ -228,6 +245,23 @@ private IEnumerable Decode(CancellationToken cancellation) } } } + private static int DecodeSpan(byte[] source, int offset, int count, long byteStart, int bom, int codePage, int previousByte) + { + for (int i = 0; i < count; i++) + { + byte value = source[offset + i]; + if (codePage == 65001) + { + if (value == 10 || value == 13) return i + 1; + } + else if (((byteStart + i - bom) & 1) != 0) + { + int prior = i == 0 ? previousByte : source[offset + i - 1]; + if (codePage == 1200 ? value == 0 && (prior == 10 || prior == 13) : prior == 0 && (value == 10 || value == 13)) return i + 1; + } + } + return count; + } // The caller owns the same file handle across scan and execution. public void Dispose() { } } diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs b/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs index b120f6e..e0cd69c 100644 --- a/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs +++ b/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs @@ -74,7 +74,11 @@ internal void Observe(MssqlImportBatch batch) if (IsWord(c)) { int start = i; - while (i < text.Length && IsWord(text[i])) i++; + while (i < text.Length && IsWord(text[i])) + { + if (text[i] == '$' && i + 1 < text.Length && text[i + 1] == '(') { currentIndex = i; throw Error("SqlCmdUnsupported"); } + i++; + } int length = i - start; if (firstCode && length == 2 && string.Compare(text, start, "GO", 0, 2, StringComparison.OrdinalIgnoreCase) == 0) throw Error("UnsupportedGo"); // Long identifiers are irrelevant unless they claim our reserved native diff --git a/tests/SmokeTests.MssqlImport.Parser.cs b/tests/SmokeTests.MssqlImport.Parser.cs index 54838be..90b4fea 100644 --- a/tests/SmokeTests.MssqlImport.Parser.cs +++ b/tests/SmokeTests.MssqlImport.Parser.cs @@ -30,6 +30,29 @@ private static void MssqlImportParserPreservesContexts() Assert(batches[0].StartLine == 1 && batches[0].EndLine == 13 && batches[1].StartLine == 15 && batches[1].EndLine == 15, "Original line offsets exclude GO delimiter."); } } + // A later malformed byte in one decoder buffer must not erase valid + // preceding line/GO transitions, including EOF decoder flush errors. + foreach(Encoding encoding in new Encoding[]{new UTF8Encoding(false,true),new UTF8Encoding(true,true),new UnicodeEncoding(false,true,true),new UnicodeEncoding(true,true,true)}) + foreach(int buffer in new[]{8192,1,2,3,7}) + foreach(int padding in new[]{0,9000}) + foreach(string newline in new[]{"\n","\r\n"}) + { + string prefix=(padding==0?"":"--"+new string(' ',padding)+newline)+"SELECT 1;"+newline+"GO"+newline+"SELECT '"+newline; + byte[] valid=ImportBytes(prefix,encoding); + bool utf8=encoding.CodePage==65001, little=encoding.CodePage==1200; + byte[][] invalid=utf8 ? new[]{new byte[]{0xff},new byte[]{0xe2,0x82}} : little ? new[]{new byte[]{0x00,0xdc},new byte[]{0x00,0xd8},new byte[]{0x41}} : new[]{new byte[]{0xdc,0x00},new byte[]{0xd8,0x00},new byte[]{0x41}}; + foreach(byte[] suffix in invalid) + using(var stream=new MemoryStream(valid.Concat(suffix).ToArray())) + using(var reader=new MssqlGoBatchReader(stream,buffer)) + { + try {reader.ReadBatches(CancellationToken.None).ToArray();Assert(false,"Malformed encoding must reject after valid GO prefix.");} + catch(MssqlImportInputException ex) + { + Assert(ex.Code=="InvalidEncoding" && ex.BatchNumber==2 && ex.Line==(padding==0?4:5) && ex.ByteOffset==valid.LongLength, + "Decoder error must preserve actual batch/line/raw byte coordinates: "+encoding.CodePage+" buffer="+buffer+" padding="+padding+" got "+ex.Message); + } + } + } using(var input = ImportInput("-- only\r\n/* nested /* ok */ end */\r\nGO\r\n-- tail")) { Assert(input.Scan(CancellationToken.None,null).BatchCount==0, "Only comments never become executable commands."); @@ -87,6 +110,10 @@ private static void MssqlImportParserUnsupported() using(var input=ImportInput(bytes)) ImportReject(input,"InvalidEncoding"); foreach(byte[] bytes in new[]{new byte[]{0x53,0,0x45,0},ImportBytes("SELECT '\0';",new UTF8Encoding(false,true)),ImportBytes("SELECT '\0';",new UnicodeEncoding(false,true,true))}) using(var input=ImportInput(bytes)) ImportReject(input,"EmbeddedNul"); + foreach(string sql in new[]{"SELECT col$(suffix) FROM dbo.t;","SELECT dbo.table$(suffix).col FROM dbo.t;","USE Transfer$(suffix);","SELECT @col$(suffix);","SELECT #tmp$(suffix);","SELECT "+new string('x',600)+"$(suffix);","SELECT 1;\nGO\nSELECT col$(suffix);"}) + using(var input=ImportInput(sql,"Transfer")) ImportReject(input,"SqlCmdUnsupported"); + using(var input=ImportInput("SELECT N'col$(suffix)', \"col$(suffix)\", [col$(suffix)], [a]]$(suffix)]; -- col$(suffix)\n/* outer /* col$(suffix) */ end */")) + Assert(input.Scan(CancellationToken.None,null).Script.Kind==MssqlImportScriptKind.Generic,"Embedded SQLCMD text remains inert in all protected lexical contexts."); using(var input=ImportInput("SELECT '$(name) :connect !!';")) Assert(input.Scan(CancellationToken.None,null).BatchCount==1,"No SQLCMD expansion in strings."); } From c0a77ea80933837c90da985e730531917dfa4a92 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 21:50:26 +0800 Subject: [PATCH 07/26] docs: record import reader acceptance and runtime handoff --- .../mssql-import/implementation-plan.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/design/mssql-import/implementation-plan.md b/docs/design/mssql-import/implementation-plan.md index fd6f4ab..01fd2e0 100644 --- a/docs/design/mssql-import/implementation-plan.md +++ b/docs/design/mssql-import/implementation-plan.md @@ -10,7 +10,7 @@ **Spec:** [design.md](design.md),使用者於 2026-10-13 回覆「好,進實作」核准書面規格。 -**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 準備中。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 +**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 已實作與覆核通過(0982548/3ebf6b3,修正兩項 P2);Task2 開始。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 **Execution:** 保留先前選定的「分工實作並逐項覆核」。一次一位 implementer,各 task 經獨立覆核後才接下一項;最後整體覆核。build、native UI 與 DB tests 由單一 owner 串行執行,避免共享輸出/fixture 衝突。 @@ -26,7 +26,7 @@ - 所有走到 EOF 的作業都做 session/交易/digest/已初始化 LOB 終態檢查,包括已略過錯誤者。native LOB 結尾要求唯一 state row、Failed=0、Consumed=1、Sequence=ConsumedThrough。 - error log 預設 `%LOCALAPPDATA%\mySQLPunk\ImportLogs\import--.log`;略過前落檔並 flush。UI 最近 100 筆或 64 KiB UTF-16 文字,先到者為準,完整路徑可見。 - 進度與 batch/line/byte/error 統計為 Int64;command/result drain/狀態處理完成才更新確認邊界。affected rows 不能標為實際匯入筆數。 -- UI 約 200 ms 合併更新;ETA 約 10 秒窗口、至少 3 次樣本與 2 秒觀察,5 秒未確認或長指令/索引/核對中改為未知。 +- UI 約 200 ms 合併更新;ETA 約 10 秒窗口、至少 3 次樣本與 2 秒觀察,5 秒未確認或長指令/索引/核對中改為未知。樣本最多64筆、200ms合併,正速率CV>1也回未知;latest counts與lastAdvance不得被節流丟失。 - Punky 自動 loop,聲音首輪一次、可靜音,沒有播放/暫停按鈕。取消、關閉與 late callback 沿用 job generation/owned resource 模式。 - 測試用既有 `mySQLPunk.SmokeTests.exe`,不執行/重建 ReportExportTests.exe,不調整防毒,不 push/merge/release。 - 大型 SQL、DB files、logs、manifest 與原始驗收證據只存 C 槽 local-only,不進 Git。使用者實檔/Transfer 不受 fixture 自動清除權限涵蓋。 @@ -70,8 +70,8 @@ - `MssqlImportPreflight`:持有 Input/Scan/Target/LogPath/Passed/固定 Code 的 Issues;IDisposable,重選與關閉時釋放 input 及未用的 job log;Run 原子領取一次 execution ownership,重用同一預檢拒絕,重複 Dispose 安全。 - `MssqlImportService(Func openSession, Func openLog)`;`Preflight(MssqlImportRequest, Action, CancellationToken): MssqlImportPreflight`;`Run(MssqlImportRequest, MssqlImportPreflight, Action, CancellationToken): MssqlImportResult`。Run 再核對 target;factory 每作業開一次專用 execution session。 - `IMssqlImportLog : IDisposable`:`string Path`、`WriteStart(request,scan,target)`、`WriteError(batch,error,action)`、`Flush()`、`WriteEnd(result)`;failure 直接向 worker 冒泡,不能吞掉後繼續。`MssqlImportLogTail.Add(string)`/`Snapshot(): string`、`long TotalErrors`。 -- `MssqlImportProgress`:`Guid JobId`、`Stage { Scanning, Executing, Verifying, Stopping, Finished }`、`long ScannedBytes/ProcessedBytes/SuccessfulBytes/SkippedBytes/SuccessfulBatches/FailedBatches`、目前 Batch/固定 Phase/可選 TableName、TimeSpan Elapsed/TimeSpan? Remaining/DateTime? EstimatedFinish;bounded string RecentErrorText/LogPath、long TotalErrors、bool LogTruncated。`MssqlImportProgressEstimator.Observe(progress, DateTime utcNow)`/`Estimate(DateTime utcNow): MssqlImportEstimate`。 -- `MssqlImportResult`:`Status { Completed, CompletedWithErrors, Failed, Cancelled, CleanupUncertain }`、統計/LastAcknowledgedBatch/UncertainBatch/LogPath/Cleanup/ValidationSummary;`MssqlImportCounts(long tables,long rows)`。`MssqlImportCleanup` 記錄是否確認 command 結束、session 釋放、未提交交易 cleanup 與固定 issue code,不把 Dispose 呼叫等同伺服器 rollback 已完成。 +- `MssqlImportProgress`:`Guid JobId`、`Stage { Scanning, Executing, Verifying, Stopping, Finished }`、`long FileBytes/ScannedBytes/ProcessedBytes/SuccessfulBytes/SkippedBytes/SuccessfulBatches/FailedBatches`、`long BatchNumber/StartLine/EndLine/StartByte/EndByte`(無目前批次為0,不能帶Batch.Text進UI)/固定 Phase/可選 TableName、TimeSpan Elapsed/TimeSpan? Remaining/DateTime? EstimatedFinish;bounded string RecentErrorText/LogPath、long TotalErrors、bool LogTruncated。`MssqlImportProgressEstimator.Observe(progress, DateTime utcNow)`/`Estimate(DateTime utcNow): MssqlImportEstimate`、`ShouldReport(MssqlImportProgress, DateTime utcNow): bool`。Estimate含TimeSpan? Remaining/DateTime? EstimatedFinish(UTC)/bool IsReliable;phase固定None/Schema/Data/Indexes/Constraints,StageVerifying/Stopping/Finished不估。 +- `MssqlImportResult`:`Status { Completed, CompletedWithErrors, Failed, Cancelled, CleanupUncertain }`、統計/LastAcknowledgedBatch/UncertainBatch/LogPath/Cleanup/ValidationSummary/TimeSpan Elapsed;`MssqlImportCounts(long tables,long rows)`。`MssqlImportCleanup` 記錄是否確認 command 結束、session 釋放、未提交交易 cleanup 與固定 issue code,不把 Dispose 呼叫等同伺服器 rollback 已完成。 ## Planning decisions that must remain explicit @@ -86,22 +86,22 @@ **Interfaces:** 產出上述 Batch/Scan/ScriptInfo/Input;inspector `Observe(MssqlImportBatch)`、`Complete(): MssqlImportScriptInfo`,保留有限 metadata,不保存完整 batches。其餘 models 在使用它的 task 補齊,不提前加入未使用的空架構。 -- [ ] **Step 1: 加入並跑失敗的 parser tests。** `MssqlImportParserPreservesContexts` 驗證字串/雙引號/方括號/巢狀 comment 中 GO 不拆;1/2/3/7-byte buffer 切在 UTF-8、BOM、CRLF、`''`、`]]` 中間仍原文相同。`MssqlImportParserLimits` 的斷言:16,777,216 code unit 的 Scan 成功且 MaxBatchCodeUnits 相等;16,777,217 時拋 MssqlImportInputException、Code="BatchTooLarge"。 -- [ ] **Step 2: 實作固定 byte/decoder buffer、bounded current batch 與 lexical line candidate。** 不用無界 ReadLine、ReadAllText/ReadAllBytes/ReadToEnd;strict decoder 的 EOF flush 要抓無效序列。明訂 EndByte 包含目前 batch 的 GO delimiter,但 SQL Text 不含 GO。純註解/空白尾段不送空 command,其 byte 覆蓋只在 EOF 驗證通過後才計入最終 ProcessedBytes=FileBytes。 -- [ ] **Step 3: 補 unsupported/native tests 並實作 inspector。** GO n、GO block comment、SQLCMD 真指令、跨庫直接 USE、未閉合 EOF、無效 encoding 拒絕;字串中的相同文字不拒絕。同 DB USE 在傳入 databaseName 且 decoded identifier 完全 Ordinal 相等時可接受;unknown target 或不同大小寫也保守拒絕,避免 case-sensitive server 的跨庫同批寫入。native Schema/DataOnly/無 LOB、正確/缺失/重複/溢位 footer、錯 job、偽造 GUID、header 不一致都要測;native candidate 不可因缺 footer 轉 generic。合法 Generic 不要求 footer。 -- [ ] **Step 4: 以同一 handle 掃描→rewind→執行第二輪,測 SHA 一致與 FileShare.Read 阻止一般寫入/刪除;檔案重選 Dispose 後可寫。** 原始 byte/line offset、無 GO 的最後批次、僅註解檔不產生可執行空 command;大檔統計使用 Int64。 -- [ ] **Step 5: 驗證並提交精確檔案。** `MYSQLPUNK_SMOKE_FILTER='MSSQL import parser'` 跑 `tests/Run-SmokeTests.ps1 -Configuration Debug`,必須 matched tests 全過;`git diff --check` 通過。Commit `feat: add bounded MSSQL GO input preflight`。 +- [x] **Step 1: 加入並跑失敗的 parser tests。** `MssqlImportParserPreservesContexts` 驗證字串/雙引號/方括號/巢狀 comment 中 GO 不拆;1/2/3/7-byte buffer 切在 UTF-8、BOM、CRLF、`''`、`]]` 中間仍原文相同。`MssqlImportParserLimits` 的斷言:16,777,216 code unit 的 Scan 成功且 MaxBatchCodeUnits 相等;16,777,217 時拋 MssqlImportInputException、Code="BatchTooLarge"。 +- [x] **Step 2: 實作固定 byte/decoder buffer、bounded current batch 與 lexical line candidate。** 不用無界 ReadLine、ReadAllText/ReadAllBytes/ReadToEnd;strict decoder 的 EOF flush 要抓無效序列。明訂 EndByte 包含目前 batch 的 GO delimiter,但 SQL Text 不含 GO。純註解/空白尾段不送空 command,其 byte 覆蓋只在 EOF 驗證通過後才計入最終 ProcessedBytes=FileBytes。 +- [x] **Step 3: 補 unsupported/native tests 並實作 inspector。** GO n、GO block comment、SQLCMD 真指令、跨庫直接 USE、未閉合 EOF、無效 encoding 拒絕;字串中的相同文字不拒絕。同 DB USE 在傳入 databaseName 且 decoded identifier 完全 Ordinal 相等時可接受;unknown target 或不同大小寫也保守拒絕,避免 case-sensitive server 的跨庫同批寫入。native Schema/DataOnly/無 LOB、正確/缺失/重複/溢位 footer、錯 job、偽造 GUID、header 不一致都要測;native candidate 不可因缺 footer 轉 generic。合法 Generic 不要求 footer。 +- [x] **Step 4: 以同一 handle 掃描→rewind→執行第二輪,測 SHA 一致與 FileShare.Read 阻止一般寫入/刪除;檔案重選 Dispose 後可寫。** 原始 byte/line offset、無 GO 的最後批次、僅註解檔不產生可執行空 command;大檔統計使用 Int64。 +- [x] **Step 5: 驗證並提交精確檔案。** `MYSQLPUNK_SMOKE_FILTER='MSSQL import parser'` 跑 `tests/Run-SmokeTests.ps1 -Configuration Debug`,必須 matched tests 全過;`git diff --check` 通過。Commit `feat: add bounded MSSQL GO input preflight`。 ## Task 2: Durable error log、bounded tail 與進度/ETA -**Files:** Create `MssqlImportLog.cs`, `MssqlImportProgressEstimator.cs`, `tests/SmokeTests.MssqlImport.Worker.cs`;補齊 Models 的 error/progress/result contracts,註冊 sources。 +**Files:** Create `MssqlImportLog.cs`, `MssqlImportProgressEstimator.cs`, `tests/SmokeTests.MssqlImport.Worker.cs`;補齊 Models 的 error/progress/result 與 log 實際消費的 Request/Target/Cleanup contracts,註冊 sources。 **Interfaces:** 產出 IMssqlImportLog/Tail/Estimator 及 terminal DTO;log 可注入 Stream factory 與 clock,測 IO 失敗不需修改檔案權限。Estimator 僅消費已確認 progress,不推測 affected rows。 - [ ] **Step 1: 加入失敗 tests。** `MssqlImportLogRetainsAllErrors` 寫入 1,283 個多 SqlError detail 的事件,磁碟都有、UI ≤100筆且 ≤32,768 chars;單筆 >64 KiB 不截完整 log。唯一檔名 CreateNew、UTF-8、包含 batch/line/byte/codes/path/job,沒有整個 SQL 或連線字串。 - [ ] **Step 2: 實作串流 log 與 tail。** Start 必須在 DB 寫入前 flush;每次準備 skip 前 flush;create/append/flush/end/Dispose fault 均可被 worker 看見。TotalErrors 不隨 UI 淘汰減少;不累積所有失敗批次,log 存開啟/資料夾/複製可用的真實路徑。 - [ ] **Step 3: 加入並實作 ETA tests。** 暖機少於 3樣本或2秒不估;約10秒窗口;5秒停滯/Indexes/Verifying 回未知;有 skip 時 Processed=Successful+Skipped、成功比例獨立;read-ahead 和執行中 batch 不算確認。測 Int64 >2 GiB/高 batch 序號、clock injected、200 ms throttle 不漏最終狀態。 -- [ ] **Step 4: 驗證 fault assertions。** `FlushFailsBeforeSkip` 預期 `NextBatchCalls==0`;密集錯誤10倍數量下 tail 記憶體固定;UI 文案顯示完整路徑且不冒稱所有資料成功。 +- [ ] **Step 4: 驗證 fault assertions。** Task2驗證Flush失敗實際向caller拋出;`FlushFailsBeforeSkip` 的 `NextBatchCalls==0` 排程斷言移交Task4真實worker,不能用test-only假worker驗證自己;密集錯誤10倍數量下 tail 記憶體固定;UI 文案顯示完整路徑且不冒稱所有資料成功。 - [ ] **Step 5: 跑 worker filter、提交。** `MYSQLPUNK_SMOKE_FILTER='MSSQL import worker'`、Debug smoke 全 matched tests 通過。Commit `feat: add MSSQL import logging and progress estimates`。 ## Task 3: Import-only owned session、target preflight 與 bounded result drain @@ -122,7 +122,7 @@ **Interfaces:** 完成 Service.Preflight/Run;Preflight 保留 input/scan/target identity/已建立 log;Run 在新專用 execution session 重查相同 server/DB id/create_date 與能力,所有 batches 同線。 -- [ ] **Step 1: 先寫失敗的 fake-session tests。** `DefaultStopsAtFirstError`、`SkipContinuesOnlySafeBatch`:未勾後續0calls;勾選一般class11–16、前後交易0/XactState0、same DB、無LOB pending、log flush成功才下一批。任何 SqlError 嚴重/timeout/傳輸/不明 outcome 不可 skip,不比對 message 語言。 +- [ ] **Step 1: 先寫失敗的 fake-session tests。** `DefaultStopsAtFirstError`、`SkipContinuesOnlySafeBatch`:未勾後續0calls;勾選一般class11–16、前後交易0/XactState0、same DB、無LOB pending、log flush成功才下一批。任何 SqlError 嚴重/timeout/傳輸/不明 outcome 不可 skip,不比對 message 語言。`FlushFailsBeforeSkip` 注入真實log flush fault,斷言 `NextBatchCalls==0`。 - [ ] **Step 2: 實作預檢→確認→執行流程。** 所有 input encoding/batch/native/目標/log 可寫性問題於第一個 DB write 前阻擋,parser失敗時execution factory calls=0;不同檔案/target/skip設定令預檢失效,ReusedPreflightIsRejected 測試第二次 Run 不送 SQL。一次一批,結果與 state 查明後才確認 bytes;目前batch可能部分生效,分開成功、失敗與未知批次。 - [ ] **Step 3: 實作 native batch role/state gate 及 EOF。** native LOB initialization/assemble/commit 任一 error fatal,即使 XACT_STATE0;普通batch遇錯也查已初始化 native state。每個走到 EOF 的作業都查交易、identity、digest、LOB唯一state/Failed0/Consumed1/Sequence=ConsumedThrough,包含 skip/DataOnly;pending/missing/wrongjob 不得 amber完成。無錯 NativeSchema 才逐表 COUNT_BIG 對 footer tables/rows,核對可取消。 - [ ] **Step 4: 實作取消/cleanup terminal tests。** 先 Stopping、不排下一批;Cancel10秒無回應只關本 session;cleanup10秒限時。自然 EOF 未結交易、取消在成功回應邊界、狀態查詢/COUNT_BIG/log flush 中取消、cleanup未確認都測。已失敗的原始結果不能被 cleanup exception 覆蓋;若最後 log失敗要顯示存檔未完整。 From 0cc16575c7a900fdd8b31dca0fe89d36deeef041 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 22:00:01 +0800 Subject: [PATCH 08/26] feat: add MSSQL import logging and progress estimates --- mySQLPunk/lib/MssqlImport/MssqlImportLog.cs | 150 +++++++++++ .../lib/MssqlImport/MssqlImportModels.cs | 150 +++++++++++ .../MssqlImportProgressEstimator.cs | 93 +++++++ mySQLPunk/mySQLPunk.csproj | 2 + tests/Run-SmokeTests.ps1 | 2 +- tests/SmokeTests.MssqlImport.Worker.cs | 234 ++++++++++++++++++ tests/SmokeTests.cs | 5 + 7 files changed, 635 insertions(+), 1 deletion(-) create mode 100644 mySQLPunk/lib/MssqlImport/MssqlImportLog.cs create mode 100644 mySQLPunk/lib/MssqlImport/MssqlImportProgressEstimator.cs create mode 100644 tests/SmokeTests.MssqlImport.Worker.cs diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportLog.cs b/mySQLPunk/lib/MssqlImport/MssqlImportLog.cs new file mode 100644 index 0000000..f42daaa --- /dev/null +++ b/mySQLPunk/lib/MssqlImport/MssqlImportLog.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + +namespace mySQLPunk.lib.MssqlImport +{ + internal interface IMssqlImportLog : IDisposable + { + string Path { get; } + // Worker snapshots this tail before publishing immutable UI progress; UI never reads the mutable tail. + MssqlImportLogTail Tail { get; } + void WriteStart(MssqlImportRequest request, MssqlImportScan scan, MssqlImportTarget target); + void WriteError(MssqlImportBatch batch, MssqlImportBatchException error, string action); + void Flush(); + void WriteEnd(MssqlImportResult result); + } + internal sealed class MssqlImportLogTail + { + private readonly Queue entries = new Queue(); + private readonly object gate = new object(); + private int characters; + private long totalErrors; + private bool truncated; + public long TotalErrors { get { lock (gate) return totalErrors; } } + public bool Truncated { get { lock (gate) return truncated; } } + public void Add(string text) + { + lock (gate) + { + totalErrors = checked(totalErrors + 1); + text = text ?? string.Empty; + if (text.Length > 32768) { text = text.Substring(text.Length - 32768); truncated = true; } + entries.Enqueue(text); characters += text.Length; + while (entries.Count > 100 || characters > 32768) + { characters -= entries.Dequeue().Length; truncated = true; } + } + } + public string Snapshot() { lock (gate) return string.Concat(entries); } + } + internal sealed class MssqlImportLog : IMssqlImportLog + { + private readonly Stream stream; + private readonly StreamWriter writer; + private readonly Func utcNow; + private bool disposed; + public string Path { get; } + public MssqlImportLogTail Tail { get; } = new MssqlImportLogTail(); + internal MssqlImportLog(Guid jobId, string directory = null, Func streamFactory = null, Func utcNow = null) + { + if (jobId == Guid.Empty) throw new ArgumentException("A job identity is required.", nameof(jobId)); + this.utcNow = utcNow ?? (() => DateTime.UtcNow); + directory = directory ?? System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "mySQLPunk", "ImportLogs"); + directory = System.IO.Path.GetFullPath(directory); + Directory.CreateDirectory(directory); + string stem = "import-" + this.utcNow().ToString("yyyyMMdd-HHmmss-fffffff", CultureInfo.InvariantCulture) + "-" + jobId.ToString("N"); + for (int collision = 0; ; collision++) + { + string suffix = collision == 0 ? string.Empty : "-" + collision.ToString(CultureInfo.InvariantCulture); + string candidate = System.IO.Path.Combine(directory, stem + suffix + ".log"); + try + { + stream = streamFactory != null ? streamFactory(candidate) : new FileStream(candidate, FileMode.CreateNew, FileAccess.Write, FileShare.Read); + Path = candidate; + break; + } + catch (IOException) when (streamFactory == null && File.Exists(candidate)) { } + } + try { writer = new StreamWriter(stream, new UTF8Encoding(false, true), 4096, true) { NewLine = "\r\n" }; } + catch { stream.Dispose(); throw; } + } + public void WriteStart(MssqlImportRequest request, MssqlImportScan scan, MssqlImportTarget target) + { + EnsureOpen(); + Field("StartUtc", utcNow().ToString("O", CultureInfo.InvariantCulture)); + Field("Job", request.JobId); Field("LogPath", Path); Field("SourcePath", request.SourcePath); + Field("FileBytes", scan.FileBytes); Field("Sha256", scan.Sha256); Field("Encoding", scan.EncodingName); + Field("SkipSqlErrors", request.SkipSqlErrors); Field("ServerName", target.ServerName); Field("DatabaseName", target.DatabaseName); + Field("DatabaseId", target.DatabaseId); Field("DatabaseCreateDate", target.DatabaseCreateDate.ToString("O", CultureInfo.InvariantCulture)); + Field("Version", target.Version); Field("Writable", target.Writable); Field("MetadataVisible", target.MetadataVisible); + Field("UserObjectCount", target.UserObjectCount); Field("CanCreateTable", target.CanCreateTable); Field("CanCreateView", target.CanCreateView); + Flush(); // The caller must not start DB writes until this durable header succeeds. + } + public void WriteError(MssqlImportBatch batch, MssqlImportBatchException error, string action) + { + EnsureOpen(); + string timestamp = utcNow().ToString("O", CultureInfo.InvariantCulture); + // Build only a bounded UI suffix. The original provider message is streamed independently. + var preview = new StringBuilder(32769); + foreach (string part in ErrorParts(batch, error, action, timestamp)) + { + int keep = Math.Min(part.Length, 32769); + if (preview.Length + keep > 32769) preview.Remove(0, preview.Length + keep - 32769); + preview.Append(part, part.Length - keep, keep); + } + Tail.Add(preview.ToString()); + foreach (string part in ErrorParts(batch, error, action, timestamp)) writer.Write(part); + } + private static IEnumerable ErrorParts(MssqlImportBatch batch, MssqlImportBatchException error, string action, string timestamp) + { + yield return "ErrorUtc=" + timestamp + " Batch=" + Number(batch.Number) + " StartLine=" + Number(batch.StartLine) + + " EndLine=" + Number(batch.EndLine) + " StartByte=" + Number(batch.StartByte) + " EndByte=" + Number(batch.EndByte) + + " OutcomeUncertain=" + error.OutcomeUncertain + " Action=" + action + "\r\n"; + foreach (var detail in error.Errors) + { + long? sourceLine = detail.RelativeLine > 0 && batch.StartLine <= long.MaxValue - detail.RelativeLine + 1 + ? (long?)(batch.StartLine + ((long)detail.RelativeLine - 1)) : null; + yield return "Number=" + detail.Number.ToString(CultureInfo.InvariantCulture) + " State=" + detail.State.ToString(CultureInfo.InvariantCulture) + + " Class=" + detail.Class.ToString(CultureInfo.InvariantCulture) + " RelativeLine=" + detail.RelativeLine.ToString(CultureInfo.InvariantCulture) + + " SourceLine=" + (sourceLine.HasValue ? Number(sourceLine.Value) : "unknown") + " Message="; + yield return detail.Message; + yield return "\r\n"; + } + } + public void Flush() + { + EnsureOpen(); writer.Flush(); + var file = stream as FileStream; + if (file != null) file.Flush(true); else stream.Flush(); + } + public void WriteEnd(MssqlImportResult result) + { + EnsureOpen(); + Field("EndUtc", utcNow().ToString("O", CultureInfo.InvariantCulture)); Field("Job", result.JobId); Field("Status", result.Status); + Field("FileBytes", result.FileBytes); Field("ProcessedBytes", result.ProcessedBytes); Field("SuccessfulBytes", result.SuccessfulBytes); + Field("SkippedBytes", result.SkippedBytes); Field("SuccessfulBatches", result.SuccessfulBatches); Field("FailedBatches", result.FailedBatches); + Field("LastAcknowledgedBatch", result.LastAcknowledgedBatch); Field("UncertainBatch", result.UncertainBatch); Field("TotalErrors", result.TotalErrors); + Field("LogPath", Path); Field("Elapsed", result.Elapsed); Field("ValidationSummary", result.ValidationSummary); + if (result.Cleanup != null) + { + Field("CommandEnded", result.Cleanup.CommandEnded); Field("SessionReleased", result.Cleanup.SessionReleased); + Field("TransactionCleanupConfirmed", result.Cleanup.TransactionCleanupConfirmed); Field("CleanupIssueCode", result.Cleanup.IssueCode); + } + else Field("Cleanup", "unknown"); + Flush(); + } + private static string Number(long value) { return value.ToString(CultureInfo.InvariantCulture); } + private void Field(string name, object value) + { writer.Write(name); writer.Write('='); writer.WriteLine(value == null ? "unknown" : Convert.ToString(value, CultureInfo.InvariantCulture)); } + private void EnsureOpen() { if (disposed) throw new ObjectDisposedException(nameof(MssqlImportLog)); } + public void Dispose() + { + if (disposed) return; + disposed = true; + try { writer.Dispose(); } + finally { stream.Dispose(); } + } + } +} diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs b/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs index 3b2a320..1a2c4f6 100644 --- a/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs +++ b/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs @@ -1,8 +1,158 @@ using System; +using System.Collections.Generic; +using System.Linq; namespace mySQLPunk.lib.MssqlImport { internal enum MssqlImportScriptKind { Generic, NativeSchema, NativeData } + internal enum MssqlImportStage { Scanning, Executing, Verifying, Stopping, Finished } + internal enum MssqlImportPhase { None, Schema, Data, Indexes, Constraints } + internal enum MssqlImportStatus { Completed, CompletedWithErrors, Failed, Cancelled, CleanupUncertain } + + internal sealed class MssqlImportRequest + { + public Guid JobId { get; } + public string SourcePath { get; } + public string DatabaseName { get; } + public bool SkipSqlErrors { get; } + internal MssqlImportRequest(Guid jobId, string sourcePath, string databaseName, bool skipSqlErrors = false) + { + if (jobId == Guid.Empty) throw new ArgumentException("A job identity is required.", nameof(jobId)); + JobId = jobId; SourcePath = sourcePath ?? string.Empty; DatabaseName = databaseName; SkipSqlErrors = skipSqlErrors; + } + } + + internal sealed class MssqlImportTarget + { + public string ServerName { get; } + public string DatabaseName { get; } + public int DatabaseId { get; } + public DateTime DatabaseCreateDate { get; } + public string Version { get; } + public bool Writable { get; } + public bool MetadataVisible { get; } + public long? UserObjectCount { get; } + public bool? CanCreateTable { get; } + public bool? CanCreateView { get; } + internal MssqlImportTarget(string serverName, string databaseName, int databaseId, DateTime databaseCreateDate, + string version, bool writable, bool metadataVisible, long? userObjectCount, bool? canCreateTable = null, bool? canCreateView = null) + { + ServerName = serverName; DatabaseName = databaseName; DatabaseId = databaseId; DatabaseCreateDate = databaseCreateDate; + Version = version; Writable = writable; MetadataVisible = metadataVisible; UserObjectCount = userObjectCount; + CanCreateTable = canCreateTable; CanCreateView = canCreateView; + } + } + + internal sealed class MssqlImportCleanup + { + public bool CommandEnded { get; } + public bool SessionReleased { get; } + public bool TransactionCleanupConfirmed { get; } + public string IssueCode { get; } + internal MssqlImportCleanup(bool commandEnded, bool sessionReleased, bool transactionCleanupConfirmed, string issueCode) + { CommandEnded = commandEnded; SessionReleased = sessionReleased; TransactionCleanupConfirmed = transactionCleanupConfirmed; IssueCode = issueCode; } + } + + internal sealed class MssqlImportSqlError + { + public int Number { get; } + public int State { get; } + public int Class { get; } + public int RelativeLine { get; } + public string Message { get; } + internal MssqlImportSqlError(int number, int state, int @class, int relativeLine, string message) + { Number = number; State = state; Class = @class; RelativeLine = relativeLine; Message = message ?? string.Empty; } + } + + internal sealed class MssqlImportBatchException : Exception + { + public IReadOnlyList Errors { get; } + public bool OutcomeUncertain { get; } + internal MssqlImportBatchException(IEnumerable errors, bool outcomeUncertain = false) + : base("MSSQL batch execution failed.") + { Errors = Array.AsReadOnly((errors ?? Enumerable.Empty()).ToArray()); OutcomeUncertain = outcomeUncertain; } + } + + internal sealed class MssqlImportProgress + { + public Guid JobId { get; } + public long FileBytes { get; } + public MssqlImportStage Stage { get; } + public MssqlImportPhase Phase { get; } + public long ScannedBytes { get; } + public long ProcessedBytes { get; } + public long SuccessfulBytes { get; } + public long SkippedBytes { get; } + public long SuccessfulBatches { get; } + public long FailedBatches { get; } + public long BatchNumber { get; } + public long StartLine { get; } + public long EndLine { get; } + public long StartByte { get; } + public long EndByte { get; } + public string TableName { get; } + public TimeSpan Elapsed { get; } + public TimeSpan? Remaining { get; } + public DateTime? EstimatedFinish { get; } + public string RecentErrorText { get; } + public string LogPath { get; } + public long TotalErrors { get; } + public bool LogTruncated { get; } + internal MssqlImportProgress(Guid jobId, long fileBytes, MssqlImportStage stage, long scannedBytes = 0, + long successfulBytes = 0, long skippedBytes = 0, long successfulBatches = 0, long failedBatches = 0, + long batchNumber = 0, long startLine = 0, long endLine = 0, long startByte = 0, long endByte = 0, + MssqlImportPhase phase = MssqlImportPhase.None, string tableName = null, TimeSpan elapsed = default(TimeSpan), + TimeSpan? remaining = null, DateTime? estimatedFinish = null, string recentErrorText = null, + string logPath = null, long totalErrors = 0, bool logTruncated = false) + { + JobId = jobId; FileBytes = fileBytes; Stage = stage; ScannedBytes = scannedBytes; + SuccessfulBytes = successfulBytes; SkippedBytes = skippedBytes; ProcessedBytes = checked(successfulBytes + skippedBytes); + SuccessfulBatches = successfulBatches; FailedBatches = failedBatches; BatchNumber = batchNumber; + StartLine = startLine; EndLine = endLine; StartByte = startByte; EndByte = endByte; Phase = phase; TableName = tableName; + Elapsed = elapsed; Remaining = remaining; EstimatedFinish = estimatedFinish; LogPath = logPath; TotalErrors = totalErrors; + string text = recentErrorText ?? string.Empty; + RecentErrorText = text.Length <= 32768 ? text : text.Substring(text.Length - 32768); + LogTruncated = logTruncated || text.Length > 32768; + } + } + + internal sealed class MssqlImportResult + { + public Guid JobId { get; } + public MssqlImportStatus Status { get; } + public long FileBytes { get; } + public long ProcessedBytes { get; } + public long SuccessfulBytes { get; } + public long SkippedBytes { get; } + public long SuccessfulBatches { get; } + public long FailedBatches { get; } + public long LastAcknowledgedBatch { get; } + public long? UncertainBatch { get; } + public string LogPath { get; } + public MssqlImportCleanup Cleanup { get; } + public string ValidationSummary { get; } + public long TotalErrors { get; } + public TimeSpan Elapsed { get; } + internal MssqlImportResult(Guid jobId, MssqlImportStatus status, long fileBytes, long successfulBytes = 0, long skippedBytes = 0, + long successfulBatches = 0, long failedBatches = 0, long lastAcknowledgedBatch = 0, long? uncertainBatch = null, + string logPath = null, MssqlImportCleanup cleanup = null, string validationSummary = null, long totalErrors = 0, + TimeSpan elapsed = default(TimeSpan)) + { + JobId = jobId; Status = status; FileBytes = fileBytes; SuccessfulBytes = successfulBytes; SkippedBytes = skippedBytes; + ProcessedBytes = checked(successfulBytes + skippedBytes); SuccessfulBatches = successfulBatches; FailedBatches = failedBatches; + LastAcknowledgedBatch = lastAcknowledgedBatch; UncertainBatch = uncertainBatch; LogPath = logPath; Cleanup = cleanup; + ValidationSummary = validationSummary; TotalErrors = totalErrors; Elapsed = elapsed; + } + } + + internal sealed class MssqlImportEstimate + { + public TimeSpan? Remaining { get; } + public DateTime? EstimatedFinish { get; } + public bool IsReliable { get; } + internal MssqlImportEstimate(TimeSpan? remaining, DateTime? estimatedFinish, bool isReliable) + { Remaining = remaining; EstimatedFinish = estimatedFinish; IsReliable = isReliable; } + } internal sealed class MssqlImportBatch { diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportProgressEstimator.cs b/mySQLPunk/lib/MssqlImport/MssqlImportProgressEstimator.cs new file mode 100644 index 0000000..556433b --- /dev/null +++ b/mySQLPunk/lib/MssqlImport/MssqlImportProgressEstimator.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; + +namespace mySQLPunk.lib.MssqlImport +{ + // Worker-only, confirmed byte boundaries; no file-position, row-count or SQL inference. + internal sealed class MssqlImportProgressEstimator + { + private sealed class Point + { + internal readonly DateTime Time; + internal readonly long Bytes; + internal Point(DateTime time, long bytes) { Time = time; Bytes = bytes; } + } + private readonly List samples = new List(64); + private MssqlImportProgress latest; + private DateTime observedAt; + private DateTime? lastAdvance; + private bool reported; + private Guid reportedJob; + private MssqlImportStage reportedStage; + private DateTime reportedAt; + + internal void Observe(MssqlImportProgress progress, DateTime utcNow) + { + if (progress == null) throw new ArgumentNullException(nameof(progress)); + bool reset = latest == null || latest.JobId != progress.JobId || latest.FileBytes != progress.FileBytes || + utcNow < observedAt || progress.ProcessedBytes < latest.ProcessedBytes; + long previous = reset ? 0 : latest.ProcessedBytes; + if (reset) { samples.Clear(); lastAdvance = null; } + latest = progress; observedAt = utcNow; + if (!CanEstimate(progress)) { samples.Clear(); lastAdvance = null; return; } + if (progress.ProcessedBytes > previous) + { + // Update confirmed counters/timestamp even when a UI report or rate sample is throttled. + lastAdvance = utcNow; + if (samples.Count == 0 || utcNow - samples[samples.Count - 1].Time >= TimeSpan.FromMilliseconds(200)) + samples.Add(new Point(utcNow, progress.ProcessedBytes)); + } + Trim(utcNow); + } + private void Trim(DateTime utcNow) + { + DateTime cutoff = utcNow > DateTime.MinValue.AddSeconds(10) ? utcNow.AddSeconds(-10) : DateTime.MinValue; + // Keep one sample at/before the window boundary so an interval remains measurable. + while (samples.Count > 1 && samples[1].Time <= cutoff) samples.RemoveAt(0); + while (samples.Count > 64) samples.RemoveAt(0); + } + private static bool CanEstimate(MssqlImportProgress progress) + { + return progress.Stage == MssqlImportStage.Executing && progress.Phase != MssqlImportPhase.Indexes && + progress.Phase != MssqlImportPhase.Constraints; + } + private static MssqlImportEstimate Unknown() { return new MssqlImportEstimate(null, null, false); } + internal MssqlImportEstimate Estimate(DateTime utcNow) + { + if (latest == null || !CanEstimate(latest) || !lastAdvance.HasValue || utcNow < observedAt || + utcNow - lastAdvance.Value >= TimeSpan.FromSeconds(5) || latest.ProcessedBytes < 0 || + latest.FileBytes <= latest.ProcessedBytes) return Unknown(); + Trim(utcNow); + if (samples.Count < 3) return Unknown(); + Point first = samples[0], last = samples[samples.Count - 1]; + double span = (last.Time - first.Time).TotalSeconds; + if (span < 2) return Unknown(); + double rateSum = 0, rateSquares = 0; + int rates = 0; + for (int i = 1; i < samples.Count; i++) + { + double rate = (samples[i].Bytes - samples[i - 1].Bytes) / (samples[i].Time - samples[i - 1].Time).TotalSeconds; + if (rate <= 0) continue; + rateSum += rate; rateSquares += rate * rate; rates++; + } + if (rates == 0) return Unknown(); + double mean = rateSum / rates; + double deviation = Math.Sqrt(Math.Max(0, rateSquares / rates - mean * mean)); + if (deviation / mean > 1) return Unknown(); + double speed = (last.Bytes - first.Bytes) / span; + double seconds = (latest.FileBytes - latest.ProcessedBytes) / speed; + if (speed <= 0 || double.IsNaN(seconds) || double.IsInfinity(seconds) || seconds < 0 || + seconds >= TimeSpan.MaxValue.TotalSeconds || seconds >= (DateTime.MaxValue - utcNow).TotalSeconds) return Unknown(); + return new MssqlImportEstimate(TimeSpan.FromSeconds(seconds), utcNow.AddSeconds(seconds), true); + } + internal bool ShouldReport(MssqlImportProgress progress, DateTime utcNow) + { + if (progress == null) throw new ArgumentNullException(nameof(progress)); + bool force = !reported || reportedJob != progress.JobId || reportedStage != progress.Stage || + progress.Stage == MssqlImportStage.Finished || utcNow < reportedAt; + if (!force && utcNow - reportedAt < TimeSpan.FromMilliseconds(200)) return false; + reported = true; reportedJob = progress.JobId; reportedStage = progress.Stage; reportedAt = utcNow; + return true; + } + } +} diff --git a/mySQLPunk/mySQLPunk.csproj b/mySQLPunk/mySQLPunk.csproj index 9a45284..77e1478 100644 --- a/mySQLPunk/mySQLPunk.csproj +++ b/mySQLPunk/mySQLPunk.csproj @@ -364,6 +364,8 @@ + + diff --git a/tests/Run-SmokeTests.ps1 b/tests/Run-SmokeTests.ps1 index 03be78b..70da1df 100644 --- a/tests/Run-SmokeTests.ps1 +++ b/tests/Run-SmokeTests.ps1 @@ -143,7 +143,7 @@ if (!(Test-Path -LiteralPath $mysqlConnector)) { /r:System.Core.dll ` /r:System.IO.Compression.dll ` /r:System.IO.Compression.FileSystem.dll ` - (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Parser.cs") $source $preferencesSource $schemaSyncSource $erModelSource (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Snapshot.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Schema.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.ViewReferences.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Properties.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Artifact.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Values.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Lob.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Routing.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.SnapshotIntegration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.CompatibilityIntegration.cs") + (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Parser.cs") $source $preferencesSource $schemaSyncSource $erModelSource (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Snapshot.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Schema.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.ViewReferences.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Properties.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Artifact.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Values.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Lob.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Routing.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.SnapshotIntegration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.CompatibilityIntegration.cs") if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/tests/SmokeTests.MssqlImport.Worker.cs b/tests/SmokeTests.MssqlImport.Worker.cs new file mode 100644 index 0000000..55236fe --- /dev/null +++ b/tests/SmokeTests.MssqlImport.Worker.cs @@ -0,0 +1,234 @@ +using System; +using System.IO; +using System.Text; +using mySQLPunk.lib.MssqlImport; +public static partial class SmokeTests +{ + // Breaks caught: overwriting a prior job log, losing provider details, logging whole SQL, or buffering start/terminal records. + private static void MssqlImportLogRetainsAllErrors() + { + string dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "mySQLPunk", "ImportTestFixtures", Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(dir); + var utc = new DateTime(2026, 10, 13, 0, 0, 0, DateTimeKind.Utc); + var request = new MssqlImportRequest(ImportProgressJob, @"C:\fixture\large.sql", "fixture", true); + var scan = new MssqlImportScan(4478414151L, 2147483650L, 20, "UTF-8", "abcd", new MssqlImportScriptInfo(MssqlImportScriptKind.Generic, null, null, null, null, false)); + var target = new MssqlImportTarget("fixture-server", "fixture", 7, utc, "15.0", true, false, null); + string firstPath = null, secondPath = null; + try { + using (var log = new MssqlImportLog(ImportProgressJob, dir, utcNow: () => utc)) { + firstPath = log.Path; + log.WriteStart(request, scan, target); + Assert(new FileInfo(firstPath).Length > 0, "Start is flushed before a caller can execute SQL."); + for (int i = 0; i < 1283; i++) { + string message = i == 0 ? "large=" + new string('z', 70000) + ";message-end" : "event=" + i + ";羽山"; + var details = new[] { new MssqlImportSqlError(50000, 1, 16, 2, message), new MssqlImportSqlError(547, 2, 16, 9, "detail=" + i) }; + var error = new MssqlImportBatchException(details); + details[0] = new MssqlImportSqlError(0, 0, 0, 0, "mutated provider buffer"); + log.WriteError(new MssqlImportBatch(2147483649L + i, 3000000000L, 3000000010L, 4000000000L, 4000000009L, "SELECT confidential-entire-sql"), error, + "Skip;TransactionCount=0;XactState=0;DatabaseId=7"); + log.Flush(); + } + IMssqlImportLog contract = log; + Assert(contract.Tail.TotalErrors == 1283 && contract.Tail.Snapshot().Length <= 32768, "Log factory interface exposes bounded UI history independently of disk history."); + log.WriteEnd(new MssqlImportResult(ImportProgressJob, MssqlImportStatus.CompletedWithErrors, 4478414151L, + successfulBytes: 3000000000L, skippedBytes: 1478414151L, successfulBatches: 2147483649L, failedBatches: 1283, + lastAcknowledgedBatch: 2147483650L, logPath: firstPath, cleanup: new MssqlImportCleanup(true, true, true, null), + validationSummary: "Batch execution complete; skipped failures prevent full validation.", totalErrors: 1283, elapsed: TimeSpan.FromSeconds(42))); + string text; + using (var file = new FileStream(firstPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + Assert(file.ReadByte() == 0x53, "New logs use UTF8 without an inserted BOM."); + file.Position = 0; + using (var reader = new StreamReader(file, new UTF8Encoding(false, true), false)) text = reader.ReadToEnd(); + } + Assert(text.Contains(new string('z', 70000) + ";message-end"), "One oversized provider message is complete on disk."); + for (int i = 0; i < 1283; i++) Assert(text.Contains("detail=" + i + "\r\n"), "Every provider detail reaches disk: " + i); + Assert(text.Contains("2147483649") && text.Contains("3000000000") && text.Contains("4000000000"), "Batch/byte/line coordinates retain Int64 values."); + Assert(text.Contains("50000") && text.Contains("547") && text.Contains("4000000001"), "All error codes and translated source lines are logged."); + Assert(text.Contains(request.SourcePath) && text.Contains(ImportProgressJob.ToString()) && text.Contains(firstPath), "Start identifies source/job/real log path."); + Assert(!text.Contains("confidential-entire-sql"), "Logging does not add SQL batch text."); + Assert(text.Contains("event=1282;羽山") && !text.Contains("mutated provider buffer"), "UTF8 messages and immutable current-command detail copies survive logging."); + Assert(text.Contains("CompletedWithErrors") && text.Contains("TransactionCleanupConfirmed=True"), "Terminal log preserves partial status and confirmed cleanup facts."); + } + using (var second = new MssqlImportLog(ImportProgressJob, dir, utcNow: () => utc)) { + secondPath = second.Path; + Assert(secondPath != firstPath && File.Exists(firstPath) && File.Exists(secondPath), "Same job/clock still uses distinct CreateNew files."); + } + } finally { + if (firstPath != null && File.Exists(firstPath)) File.Delete(firstPath); + if (secondPath != null && File.Exists(secondPath)) File.Delete(secondPath); + Directory.Delete(dir); + } + } + // Breaks caught: using scanned/current-batch bytes, clock time alone, or every callback as a confirmed sample. + private static readonly Guid ImportProgressJob = new Guid("10000000-0000-0000-0000-000000000001"); + private static MssqlImportProgress ImportProgress(long success, long skipped = 0, long total = 1000, + MssqlImportStage stage = MssqlImportStage.Executing, MssqlImportPhase phase = MssqlImportPhase.Data, + long scanned = 0, long batch = 0, long end = 0) + { + return new MssqlImportProgress(ImportProgressJob, total, stage, scannedBytes: scanned, + successfulBytes: success, skippedBytes: skipped, batchNumber: batch, endByte: end, phase: phase); + } + private static void MssqlImportProgressEstimatesConfirmedBytes() + { + var clock = new DateTime(2026, 10, 13, 0, 0, 0, DateTimeKind.Utc); + var estimator = new MssqlImportProgressEstimator(); + estimator.Observe(ImportProgress(100), clock); + estimator.Observe(ImportProgress(200), clock.AddSeconds(1)); + Assert(!estimator.Estimate(clock.AddSeconds(1)).IsReliable, "Two confirmations do not estimate."); + estimator.Observe(ImportProgress(300), clock.AddSeconds(2)); + var known = estimator.Estimate(clock.AddSeconds(2)); + Assert(known.IsReliable && Math.Abs(known.Remaining.Value.TotalSeconds - 7) < 0.01, + "Three confirmations over two seconds measure 100 bytes/sec and seven seconds remain."); + Assert(known.EstimatedFinish == clock.AddSeconds(9), "Estimated finish is an absolute UTC estimate."); + estimator.Observe(ImportProgress(300, scanned: 1000, batch: 2147483649, end: 1000), clock.AddSeconds(6)); + Assert(estimator.Estimate(clock.AddSeconds(6)).IsReliable, "Read-ahead/inflight coordinate changes do not invent throughput samples."); + Assert(!estimator.Estimate(clock.AddSeconds(7)).IsReliable, "Five seconds since confirmed advancement becomes unknown."); + foreach (MssqlImportPhase phase in new[] { MssqlImportPhase.Indexes, MssqlImportPhase.Constraints }) { + estimator.Observe(ImportProgress(400, phase: phase), clock.AddSeconds(8)); + Assert(!estimator.Estimate(clock.AddSeconds(8)).IsReliable, "Indexes and constraints have no byte ETA."); + } + foreach (MssqlImportStage stage in new[] { MssqlImportStage.Verifying, MssqlImportStage.Stopping, MssqlImportStage.Finished }) { + estimator.Observe(ImportProgress(1000, stage: stage), clock.AddSeconds(9)); + Assert(!estimator.Estimate(clock.AddSeconds(9)).IsReliable, "Verification/stopping/finished do not present file-byte ETA."); + } + var skipped = new MssqlImportProgressEstimator(); + skipped.Observe(ImportProgress(100, 100), clock); + skipped.Observe(ImportProgress(200, 200), clock.AddSeconds(1)); + skipped.Observe(ImportProgress(300, 300), clock.AddSeconds(2)); + Assert(Math.Abs(skipped.Estimate(clock.AddSeconds(2)).Remaining.Value.TotalSeconds - 2) < 0.01, + "Processed bytes include failed/skipped coverage, independently of successful bytes."); + var big = new MssqlImportProgressEstimator(); + big.Observe(ImportProgress(3000000000L, total: 6000000000L), clock); + big.Observe(ImportProgress(3500000000L, total: 6000000000L), clock.AddSeconds(1)); + big.Observe(ImportProgress(4000000000L, total: 6000000000L), clock.AddSeconds(2)); + Assert(big.Estimate(clock.AddSeconds(2)).Remaining.Value.TotalSeconds == 4, "Int64 byte progress cannot wrap at 2GiB."); + } + // Breaks caught: retaining every error, capping only event count, or decrementing the total on eviction. + private static void MssqlImportLogTailIsBounded() + { + foreach (int count in new[] { 1283, 12830 }) + { + var tail = new MssqlImportLogTail(); + for (int i = 0; i < count; i++) tail.Add("event=" + i + ";" + new string('x', 1000) + "\r\n"); + string snapshot = tail.Snapshot(); + Assert(tail.TotalErrors == count, "Total SQL error events survives UI eviction."); + Assert(snapshot.Length <= 32768, "UTF16 UI text is at most 64KiB for either workload."); + Assert(snapshot.Contains("event=" + (count - 1) + ";"), "The latest error is visible."); + Assert(!snapshot.Contains("event=0;"), "Old error records are evicted."); + } + var small = new MssqlImportLogTail(); + for (int i = 0; i < 1283; i++) small.Add("event=" + i + ";\r\n"); + Assert(!small.Snapshot().Contains("event=1182;") && small.Snapshot().Contains("event=1183;"), "Only the newest 100 short records remain."); + var oversized = new MssqlImportLogTail(); + oversized.Add("HEAD" + new string('x', 100000) + "LAST DETAIL"); + Assert(oversized.Snapshot().Length <= 32768 && oversized.Snapshot().EndsWith("LAST DETAIL"), "One large event is truncated only in UI and retains its latest detail."); + Assert(oversized.TotalErrors == 1, "One oversized event still counts once."); + } + + // Breaks caught: swallowed persistence errors or a writer flush failure preventing the owned stream from closing. + private sealed class ImportFaultStream : MemoryStream + { + internal bool FailWrite, FailFlush, FailDispose, Released; + public override void Write(byte[] buffer, int offset, int count) + { if (FailWrite) throw new IOException("injected append failure"); base.Write(buffer, offset, count); } + public override void Flush() + { if (FailFlush) throw new IOException("injected flush failure"); base.Flush(); } + protected override void Dispose(bool disposing) + { Released = true; base.Dispose(disposing); if (FailDispose) throw new IOException("injected disposal failure"); } + } + private static void ImportExpectIo(Action action, string reason) + { + bool failed = false; + try { action(); } catch (IOException) { failed = true; } + Assert(failed, reason); + } + private static void MssqlImportLogFaultsPropagate() + { + string dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "mySQLPunk", "ImportTestFixtures", Guid.NewGuid().ToString("N")); + var utc = new DateTime(2026, 10, 13, 0, 0, 0, DateTimeKind.Utc); + var request = new MssqlImportRequest(ImportProgressJob, null, "fixture"); + var scan = new MssqlImportScan(10, 1, 10, "UTF-8", "abcd", null); + var target = new MssqlImportTarget("fixture", "fixture", 7, utc, "15", true, false, null); + var result = new MssqlImportResult(ImportProgressJob, MssqlImportStatus.CleanupUncertain, 10, + cleanup: new MssqlImportCleanup(false, false, false, "SessionReleaseUnconfirmed")); + try { + ImportExpectIo(() => new MssqlImportLog(ImportProgressJob, dir, p => { throw new IOException("injected create failure"); }), "Create failure reaches caller."); + foreach (string fault in new[] { "start-write", "start-flush", "append", "flush", "end", "dispose-flush", "dispose-stream" }) { + var stream = new ImportFaultStream(); + var log = new MssqlImportLog(ImportProgressJob, dir, p => stream, () => utc); + try { + if (fault == "start-write" || fault == "start-flush") { + stream.FailWrite = fault == "start-write"; stream.FailFlush = fault == "start-flush"; + ImportExpectIo(() => log.WriteStart(request, scan, target), "Start persistence fails before SQL can begin: " + fault); + } else { + log.WriteStart(request, scan, target); + if (fault == "append") { + stream.FailWrite = true; + ImportExpectIo(() => log.WriteError(new MssqlImportBatch(1, 0, 10, 1, 1, "private SQL"), + new MssqlImportBatchException(new[] { new MssqlImportSqlError(547, 1, 16, 1, new string('x', 70000) + "latest-detail") }), "Stop"), "Append failure reaches caller."); + Assert(log.Tail.TotalErrors == 1 && log.Tail.Snapshot().Contains("latest-detail"), "Current error remains in bounded UI tail when disk append fails."); + } else if (fault == "flush") { + stream.FailFlush = true; + ImportExpectIo(log.Flush, "Flush failure reaches actual caller; scheduling assertion belongs to Task4 service."); + } else if (fault == "end") { + stream.FailFlush = true; + ImportExpectIo(() => log.WriteEnd(result), "Terminal persistence failure cannot appear successful."); + } else { + stream.FailFlush = fault == "dispose-flush"; stream.FailDispose = fault == "dispose-stream"; + ImportExpectIo(log.Dispose, "Dispose failure remains visible: " + fault); + Assert(stream.Released, "Raw stream is released even if StreamWriter disposal fails."); + log.Dispose(); + } + } + } finally { stream.FailWrite = stream.FailFlush = stream.FailDispose = false; log.Dispose(); } + Assert(stream.Released, "Every fault path releases the owned stream."); + } + } finally { Directory.Delete(dir); } + } + + // Breaks caught: unbounded sample history, stale old rates, discarded throttled confirmations, or missing final callback. + private static void MssqlImportProgressWindowAndThrottle() + { + var utc = new DateTime(2026, 10, 13, 0, 0, 0, DateTimeKind.Utc); + var warm = new MssqlImportProgressEstimator(); + warm.Observe(ImportProgress(100), utc); + warm.Observe(ImportProgress(200), utc.AddMilliseconds(200)); + warm.Observe(ImportProgress(300), utc.AddMilliseconds(400)); + Assert(!warm.Estimate(utc.AddMilliseconds(400)).IsReliable, "Three rapid confirmations still require two seconds of observation."); + var volatileRate = new MssqlImportProgressEstimator(); + volatileRate.Observe(ImportProgress(1, total: 100000), utc); + volatileRate.Observe(ImportProgress(2, total: 100000), utc.AddSeconds(1)); + volatileRate.Observe(ImportProgress(3, total: 100000), utc.AddSeconds(2)); + volatileRate.Observe(ImportProgress(10003, total: 100000), utc.AddSeconds(3)); + Assert(!volatileRate.Estimate(utc.AddSeconds(3)).IsReliable, "Positive interval-rate coefficient of variation above one suppresses ETA."); + var window = new MssqlImportProgressEstimator(); + window.Observe(ImportProgress(100, total: 100000), utc); + window.Observe(ImportProgress(200, total: 100000), utc.AddSeconds(1)); + window.Observe(ImportProgress(300, total: 100000), utc.AddSeconds(2)); + for (int second = 3; second <= 15; second++) window.Observe(ImportProgress(300 + (second - 2) * 1000, total: 100000), utc.AddSeconds(second)); + Assert(Math.Abs(window.Estimate(utc.AddSeconds(15)).Remaining.Value.TotalSeconds - 86.7) < 0.01, + "Rates older than the approximately ten-second window no longer dominate."); + var dense = new MssqlImportProgressEstimator(); + for (int ms = 0; ms <= 3000; ms++) dense.Observe(ImportProgress(ms + 1, total: 100000), utc.AddMilliseconds(ms)); + dense.Observe(ImportProgress(3100, total: 100000), utc.AddMilliseconds(3100)); + Assert(dense.Estimate(utc.AddMilliseconds(3100)).IsReliable, "Dense callbacks are coalesced while latest confirmed totals are retained."); + Assert(dense.Estimate(utc.AddMilliseconds(8000)).IsReliable, "A coalesced last confirmation refreshes the five-second stall boundary."); + Assert(!dense.Estimate(utc.AddMilliseconds(8100)).IsReliable, "Exactly five seconds since that confirmation becomes unknown."); + var gate = new MssqlImportProgressEstimator(); + Assert(gate.ShouldReport(ImportProgress(0, stage: MssqlImportStage.Scanning), utc), "First callback is visible."); + Assert(!gate.ShouldReport(ImportProgress(0, stage: MssqlImportStage.Scanning), utc.AddMilliseconds(199)), "Same-stage callback is throttled below 200ms."); + Assert(gate.ShouldReport(ImportProgress(0, stage: MssqlImportStage.Scanning), utc.AddMilliseconds(200)), "The 200ms boundary reports."); + Assert(gate.ShouldReport(ImportProgress(100), utc.AddMilliseconds(201)), "A stage change is visible immediately."); + Assert(gate.ShouldReport(ImportProgress(1000, stage: MssqlImportStage.Finished), utc.AddMilliseconds(202)), "Final status cannot be lost to throttling."); + var readAhead = new MssqlImportProgressEstimator(); + for (int second = 0; second < 3; second++) readAhead.Observe(ImportProgress(0, scanned: 1000, batch: second + 1, end: 1000), utc.AddSeconds(second)); + Assert(!readAhead.Estimate(utc.AddSeconds(2)).IsReliable, "Read-ahead and currently executing batches contribute no confirmed work."); + var capped = new MssqlImportProgress(ImportProgressJob, 1000, MssqlImportStage.Finished, + successfulBytes: 400, skippedBytes: 600, recentErrorText: new string('x', 70000), logPath: @"C:\actual\import.log", totalErrors: 1283); + Assert(capped.ProcessedBytes == 1000 && capped.SuccessfulBytes == 400 && capped.RecentErrorText.Length <= 32768 && capped.LogTruncated, + "Progress snapshots preserve separate successful coverage and bound a caller-supplied UI tail."); + Assert(capped.LogPath == @"C:\actual\import.log" && capped.TotalErrors == 1283, "Full path and lifetime error count accompany the bounded snapshot."); + } + +} diff --git a/tests/SmokeTests.cs b/tests/SmokeTests.cs index 456f8d4..1d474d4 100644 --- a/tests/SmokeTests.cs +++ b/tests/SmokeTests.cs @@ -31,6 +31,11 @@ public static int Main(string[] args) if (args.Length != 0) return SnapshotCrashChild(args); if (Environment.GetEnvironmentVariable("MYSQLPUNK_MSSQL_WIZARD_PREVIEW") == "1") return WizardPreview(); int passed = 0; + Run("MSSQL import worker log faults", MssqlImportLogFaultsPropagate, ref passed); + Run("MSSQL import worker window and throttle", MssqlImportProgressWindowAndThrottle, ref passed); + Run("MSSQL import worker tail bound", MssqlImportLogTailIsBounded, ref passed); + Run("MSSQL import worker estimates", MssqlImportProgressEstimatesConfirmedBytes, ref passed); + Run("MSSQL import worker log retention", MssqlImportLogRetainsAllErrors, ref passed); Run("MSSQL import parser contexts", MssqlImportParserPreservesContexts, ref passed); Run("MSSQL import parser limits", MssqlImportParserLimits, ref passed); Run("MSSQL import parser unsupported", MssqlImportParserUnsupported, ref passed); From 951cdd6964301cd4e2a7088db1ffd3dc668151b6 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 22:05:52 +0800 Subject: [PATCH 09/26] docs: record import logging acceptance and session handoff --- docs/design/mssql-import/implementation-plan.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/design/mssql-import/implementation-plan.md b/docs/design/mssql-import/implementation-plan.md index 01fd2e0..3d932af 100644 --- a/docs/design/mssql-import/implementation-plan.md +++ b/docs/design/mssql-import/implementation-plan.md @@ -10,7 +10,7 @@ **Spec:** [design.md](design.md),使用者於 2026-10-13 回覆「好,進實作」核准書面規格。 -**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 已實作與覆核通過(0982548/3ebf6b3,修正兩項 P2);Task2 開始。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 +**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 已實作與覆核通過(0982548/3ebf6b3,修正兩項 P2);Task2 log/ETA 已實作與覆核通過(0cc1657);Task3 開始。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 **Execution:** 保留先前選定的「分工實作並逐項覆核」。一次一位 implementer,各 task 經獨立覆核後才接下一項;最後整體覆核。build、native UI 與 DB tests 由單一 owner 串行執行,避免共享輸出/fixture 衝突。 @@ -98,11 +98,11 @@ **Interfaces:** 產出 IMssqlImportLog/Tail/Estimator 及 terminal DTO;log 可注入 Stream factory 與 clock,測 IO 失敗不需修改檔案權限。Estimator 僅消費已確認 progress,不推測 affected rows。 -- [ ] **Step 1: 加入失敗 tests。** `MssqlImportLogRetainsAllErrors` 寫入 1,283 個多 SqlError detail 的事件,磁碟都有、UI ≤100筆且 ≤32,768 chars;單筆 >64 KiB 不截完整 log。唯一檔名 CreateNew、UTF-8、包含 batch/line/byte/codes/path/job,沒有整個 SQL 或連線字串。 -- [ ] **Step 2: 實作串流 log 與 tail。** Start 必須在 DB 寫入前 flush;每次準備 skip 前 flush;create/append/flush/end/Dispose fault 均可被 worker 看見。TotalErrors 不隨 UI 淘汰減少;不累積所有失敗批次,log 存開啟/資料夾/複製可用的真實路徑。 -- [ ] **Step 3: 加入並實作 ETA tests。** 暖機少於 3樣本或2秒不估;約10秒窗口;5秒停滯/Indexes/Verifying 回未知;有 skip 時 Processed=Successful+Skipped、成功比例獨立;read-ahead 和執行中 batch 不算確認。測 Int64 >2 GiB/高 batch 序號、clock injected、200 ms throttle 不漏最終狀態。 -- [ ] **Step 4: 驗證 fault assertions。** Task2驗證Flush失敗實際向caller拋出;`FlushFailsBeforeSkip` 的 `NextBatchCalls==0` 排程斷言移交Task4真實worker,不能用test-only假worker驗證自己;密集錯誤10倍數量下 tail 記憶體固定;UI 文案顯示完整路徑且不冒稱所有資料成功。 -- [ ] **Step 5: 跑 worker filter、提交。** `MYSQLPUNK_SMOKE_FILTER='MSSQL import worker'`、Debug smoke 全 matched tests 通過。Commit `feat: add MSSQL import logging and progress estimates`。 +- [x] **Step 1: 加入失敗 tests。** `MssqlImportLogRetainsAllErrors` 寫入 1,283 個多 SqlError detail 的事件,磁碟都有、UI ≤100筆且 ≤32,768 chars;單筆 >64 KiB 不截完整 log。唯一檔名 CreateNew、UTF-8、包含 batch/line/byte/codes/path/job,沒有整個 SQL 或連線字串。 +- [x] **Step 2: 實作串流 log 與 tail。** Start 必須在 DB 寫入前 flush;每次準備 skip 前 flush;create/append/flush/end/Dispose fault 均可被 worker 看見。TotalErrors 不隨 UI 淘汰減少;不累積所有失敗批次,log 存開啟/資料夾/複製可用的真實路徑。 +- [x] **Step 3: 加入並實作 ETA tests。** 暖機少於 3樣本或2秒不估;約10秒窗口;5秒停滯/Indexes/Verifying 回未知;有 skip 時 Processed=Successful+Skipped、成功比例獨立;read-ahead 和執行中 batch 不算確認。測 Int64 >2 GiB/高 batch 序號、clock injected、200 ms throttle 不漏最終狀態。 +- [x] **Step 4: 驗證 fault assertions。** Task2驗證Flush失敗實際向caller拋出;`FlushFailsBeforeSkip` 的 `NextBatchCalls==0` 排程斷言移交Task4真實worker,不能用test-only假worker驗證自己;密集錯誤10倍數量下 tail 記憶體固定;UI 文案顯示完整路徑且不冒稱所有資料成功。 +- [x] **Step 5: 跑 worker filter、提交。** `MYSQLPUNK_SMOKE_FILTER='MSSQL import worker'`、Debug smoke 全 matched tests 通過。Commit `feat: add MSSQL import logging and progress estimates`。 ## Task 3: Import-only owned session、target preflight 與 bounded result drain From 9df6437607ff3774a1b20c671753e8b4a547f0a4 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 22:21:22 +0800 Subject: [PATCH 10/26] feat: add isolated MSSQL import session adapter --- .../lib/ConnectionConfigurationService.cs | 11 + mySQLPunk/lib/ConnectionOpenService.cs | 29 +- .../lib/MssqlImport/MssqlImportModels.cs | 29 ++ .../lib/MssqlImport/MssqlImportSession.cs | 350 ++++++++++++++++++ mySQLPunk/mySQLPunk.csproj | 1 + tests/Run-SmokeTests.ps1 | 2 +- tests/SmokeTests.MssqlImport.Integration.cs | 317 ++++++++++++++++ tests/SmokeTests.cs | 5 + 8 files changed, 742 insertions(+), 2 deletions(-) create mode 100644 mySQLPunk/lib/MssqlImport/MssqlImportSession.cs create mode 100644 tests/SmokeTests.MssqlImport.Integration.cs diff --git a/mySQLPunk/lib/ConnectionConfigurationService.cs b/mySQLPunk/lib/ConnectionConfigurationService.cs index 000902d..fd1130d 100644 --- a/mySQLPunk/lib/ConnectionConfigurationService.cs +++ b/mySQLPunk/lib/ConnectionConfigurationService.cs @@ -74,6 +74,17 @@ public static string BuildSqlServerConnectionString(Dictionary c return builder.ConnectionString; } + internal static string BuildMssqlImportConnectionString(Dictionary connection) + { + if (connection == null) throw new ArgumentNullException(nameof(connection)); + if (string.IsNullOrWhiteSpace(GetValue(connection, "initial_database"))) + throw new ArgumentException("MSSQL import requires an explicit target database.", nameof(connection)); + var builder = new SqlConnectionStringBuilder(BuildSqlServerConnectionString(connection)); + builder.ConnectRetryCount = 0; + builder.MultipleActiveResultSets = false; + return builder.ConnectionString; + } + public static string BuildMySqlConnectionString(Dictionary connection) { uint port = 3306; diff --git a/mySQLPunk/lib/ConnectionOpenService.cs b/mySQLPunk/lib/ConnectionOpenService.cs index fedfba0..eebb584 100644 --- a/mySQLPunk/lib/ConnectionOpenService.cs +++ b/mySQLPunk/lib/ConnectionOpenService.cs @@ -52,6 +52,11 @@ public static ConnectionOpenResult Open(Func databaseFactory, string } public static ConnectionOpenResult Open(Dictionary connection, bool loadDatabases = true) + { + return Open(connection, loadDatabases, false); + } + + private static ConnectionOpenResult Open(Dictionary connection, bool loadDatabases, bool importOnly) { if (connection == null) throw new ArgumentNullException("connection"); Dictionary effective = new Dictionary(connection); @@ -71,7 +76,9 @@ public static ConnectionOpenResult Open(Dictionary connection, b } string provider = ConnectionConfigurationService.NormalizeProvider(ConnectionConfigurationService.GetValue(effective, "db_kind")); - string connectionString = ConnectionConfigurationService.BuildConnectionString(effective); + string connectionString = importOnly + ? ConnectionConfigurationService.BuildMssqlImportConnectionString(effective) + : ConnectionConfigurationService.BuildConnectionString(effective); IDatabase rawDatabase = ConnectionConfigurationService.CreateDatabase(provider); database = tunnel == null ? rawDatabase : new SecuredDatabase(rawDatabase, tunnel); if (tunnel != null) tunnel = null; @@ -106,6 +113,26 @@ internal static MssqlOwnedSession OpenMssqlSession(Dictionary co } } + internal static MssqlOwnedSession OpenMssqlImportSession(Dictionary connection) + { + if (connection == null) throw new ArgumentNullException(nameof(connection)); + string provider = ConnectionConfigurationService.NormalizeProvider(ConnectionConfigurationService.GetValue(connection, "db_kind")); + if (provider != "mssql") throw new ArgumentException("MSSQL import requires a SQL Server connection", nameof(connection)); + // Validate the selected catalog before starting any SSH lease or opening a connection. + ConnectionConfigurationService.BuildMssqlImportConnectionString(connection); + ConnectionOpenResult result = Open(connection, false, true); + try + { + if (result.NativeMssqlConnection == null) throw new InvalidOperationException("SQL Server provider connection is unavailable"); + return new MssqlOwnedSession(result.Database, result.NativeMssqlConnection); + } + catch + { + try { result.Database.Dispose(); } catch { } + throw; + } + } + private static void ValidateSecurityCombination(Dictionary connection) { if (!ConnectionSecuritySettingsService.IsTrue(connection, "ssh_enabled")) return; diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs b/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs index 1a2c4f6..d61a073 100644 --- a/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs +++ b/mySQLPunk/lib/MssqlImport/MssqlImportModels.cs @@ -43,6 +43,35 @@ internal MssqlImportTarget(string serverName, string databaseName, int databaseI } } + internal sealed class MssqlImportSessionState + { + public bool IsOpen { get; } + public int DatabaseId { get; } + public int TransactionCount { get; } + public int XactState { get; } + internal MssqlImportSessionState(bool isOpen, int databaseId, int transactionCount, int xactState) + { IsOpen = isOpen; DatabaseId = databaseId; TransactionCount = transactionCount; XactState = xactState; } + } + + internal sealed class MssqlImportLobState + { + public bool Exists { get; } + public long RowCount { get; } + public long Sequence { get; } + public long ConsumedThrough { get; } + public bool Consumed { get; } + public bool Failed { get; } + internal MssqlImportLobState(bool exists, long rowCount, long sequence, long consumedThrough, bool consumed, bool failed) + { Exists = exists; RowCount = rowCount; Sequence = sequence; ConsumedThrough = consumedThrough; Consumed = consumed; Failed = failed; } + } + + internal sealed class MssqlImportCounts + { + public long Tables { get; } + public long Rows { get; } + internal MssqlImportCounts(long tables, long rows) { Tables = tables; Rows = rows; } + } + internal sealed class MssqlImportCleanup { public bool CommandEnded { get; } diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportSession.cs b/mySQLPunk/lib/MssqlImport/MssqlImportSession.cs new file mode 100644 index 0000000..7b50712 --- /dev/null +++ b/mySQLPunk/lib/MssqlImport/MssqlImportSession.cs @@ -0,0 +1,350 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Data.SqlClient; +using System.Globalization; +using System.Runtime.ExceptionServices; +using System.Threading; +using mySQLPunk.lib.MssqlExport; + +namespace mySQLPunk.lib.MssqlImport +{ + internal interface IMssqlImportSession : IDisposable + { + MssqlImportTarget ReadTarget(CancellationToken cancellation); + MssqlImportSessionState ReadState(CancellationToken cancellation); + MssqlImportLobState ReadLobState(Guid jobId, CancellationToken cancellation); + void ExecuteBatch(MssqlImportBatch batch, CancellationToken cancellation); + MssqlImportCounts CountTargetRows(Action progress, CancellationToken cancellation); + void CancelActiveCommand(); + MssqlImportCleanup Cleanup(); + } + + internal sealed class MssqlImportSqlSession : IMssqlImportSession + { + private readonly object gate = new object(); + private readonly Func createCommand; + private readonly Func isOpen; + private readonly int cancelMilliseconds; + private IDisposable owner; + private ActiveCommand active; + private bool releaseStarted, sessionReleased, cleanupRunning; + private MssqlImportCleanup cleanup; + + private sealed class ActiveCommand + { + internal readonly DbCommand Command; + internal CancellationTokenRegistration Registration; + internal Timer Watchdog; + internal bool CancellationRequested; + internal ActiveCommand(DbCommand command) { Command = command; } + } + + internal MssqlImportSqlSession(MssqlOwnedSession owner) + : this(owner, () => owner.Connection.CreateCommand(), () => owner.Connection.State == ConnectionState.Open) { } + + // The test seam substitutes only this connection's command factory and lifetime, never a shared provider. + internal MssqlImportSqlSession(IDisposable owner, Func createCommand, Func isOpen, int cancelMilliseconds = 10000) + { + try + { + if (owner == null) throw new ArgumentNullException(nameof(owner)); + if (createCommand == null) throw new ArgumentNullException(nameof(createCommand)); + if (isOpen == null) throw new ArgumentNullException(nameof(isOpen)); + if (cancelMilliseconds <= 0) throw new ArgumentOutOfRangeException(nameof(cancelMilliseconds)); + this.owner = owner; this.createCommand = createCommand; this.isOpen = isOpen; this.cancelMilliseconds = cancelMilliseconds; + } + catch { try { if (owner != null) owner.Dispose(); } catch { } throw; } + } + + public MssqlImportTarget ReadTarget(CancellationToken cancellation) + { + object[] identity = ReadValues(@"SELECT CONVERT(nvarchar(128),SERVERPROPERTY('ServerName')),DB_NAME(),DB_ID(), +(SELECT create_date FROM sys.databases WHERE database_id=DB_ID()), +CONVERT(nvarchar(128),SERVERPROPERTY('ProductVersion')), +CONVERT(nvarchar(60),DATABASEPROPERTYEX(DB_NAME(),'Updateability')),USER_ID(), +HAS_PERMS_BY_NAME(DB_NAME(),'DATABASE','VIEW DEFINITION'), +HAS_PERMS_BY_NAME(DB_NAME(),'DATABASE','CREATE TABLE'),HAS_PERMS_BY_NAME(DB_NAME(),'DATABASE','CREATE VIEW');", 5, cancellation); + if (identity == null || identity.Length != 10 || Missing(identity[0]) || Missing(identity[1]) || Missing(identity[2]) || Missing(identity[3]) || Missing(identity[4])) + throw new InvalidOperationException("TargetIdentityUnavailable"); + string server = Convert.ToString(identity[0], CultureInfo.InvariantCulture); + string database = Convert.ToString(identity[1], CultureInfo.InvariantCulture); + string version = Convert.ToString(identity[4], CultureInfo.InvariantCulture); + int databaseId = Convert.ToInt32(identity[2], CultureInfo.InvariantCulture), major; + if (string.IsNullOrWhiteSpace(server) || string.IsNullOrWhiteSpace(database) || databaseId <= 0 || + !int.TryParse(version.Split('.')[0], NumberStyles.None, CultureInfo.InvariantCulture, out major) || major <= 0 || !(identity[3] is DateTime)) + throw new InvalidOperationException("TargetIdentityUnavailable"); + bool complete = !Missing(identity[6]) && Convert.ToInt32(identity[6], CultureInfo.InvariantCulture) == 1; + long? count = null; + try + { + if (!complete && Permission(identity[7]) == true) + { + bool securityVisible = major < 16 || Permission(Scalar("SELECT HAS_PERMS_BY_NAME(DB_NAME(),'DATABASE','VIEW SECURITY DEFINITION');", 5, cancellation)) == true; + if (securityVisible) + { + // Scan raw permission rows for the whole effective token, including roles/public/Windows groups. + // Joining objects here could hide the very DENY that makes an apparent empty catalog unsafe. + object denied = Scalar(@"SELECT COUNT_BIG(*) FROM sys.database_permissions AS p +WHERE p.state='D' AND p.grantee_principal_id IN (SELECT principal_id FROM sys.user_token);", 5, cancellation); + complete = !Missing(denied) && Convert.ToInt64(denied, CultureInfo.InvariantCulture) == 0; + } + } + if (complete) + { + object objects = Scalar("SELECT COUNT_BIG(*) FROM sys.objects WHERE is_ms_shipped=0;", 5, cancellation); + if (!Missing(objects) && Convert.ToInt64(objects, CultureInfo.InvariantCulture) >= 0) count = Convert.ToInt64(objects, CultureInfo.InvariantCulture); + else complete = false; + } + } + catch (MssqlImportBatchException error) + { + // Lack of metadata is acceptable for Generic/DataOnly, but a broken/cancelled session is not. + if (error.OutcomeUncertain || cancellation.IsCancellationRequested || !ConnectionUsable()) throw; + complete = false; count = null; + } + return new MssqlImportTarget(server, database, databaseId, (DateTime)identity[3], version, + string.Equals(Convert.ToString(identity[5], CultureInfo.InvariantCulture), "READ_WRITE", StringComparison.OrdinalIgnoreCase), + complete, complete ? count : null, Permission(identity[8]), Permission(identity[9])); + } + + public MssqlImportSessionState ReadState(CancellationToken cancellation) + { + cancellation.ThrowIfCancellationRequested(); + EnsureNoActiveCommand(); + if (!ConnectionUsable()) return new MssqlImportSessionState(false, 0, 0, 0); + object[] state = ReadValues("SELECT DB_ID(),@@TRANCOUNT,XACT_STATE();", 5, cancellation); + if (state == null || state.Length != 3 || Missing(state[0]) || Missing(state[1]) || Missing(state[2]) || Convert.ToInt32(state[0], CultureInfo.InvariantCulture) <= 0) + throw new InvalidOperationException("SessionStateUnavailable"); + return new MssqlImportSessionState(true, Convert.ToInt32(state[0], CultureInfo.InvariantCulture), + Convert.ToInt32(state[1], CultureInfo.InvariantCulture), Convert.ToInt32(state[2], CultureInfo.InvariantCulture)); + } + + public MssqlImportLobState ReadLobState(Guid jobId, CancellationToken cancellation) + { + if (jobId == Guid.Empty) throw new ArgumentException("A native LOB job identity is required.", nameof(jobId)); + string name = "#mp_" + jobId.ToString("N") + "_s"; + object[] state = ReadValues("IF OBJECT_ID(N'tempdb.." + name + "') IS NULL " + + "SELECT CAST(0 AS bit),CAST(0 AS bigint),CAST(0 AS bigint),CAST(0 AS bigint),CAST(0 AS bit),CAST(0 AS bit); " + + "ELSE SELECT CAST(1 AS bit),COUNT_BIG(*),COALESCE(MAX([Sequence]),0),COALESCE(MAX([ConsumedThrough]),0)," + + "CAST(COALESCE(MIN(CAST([Consumed] AS int)),0) AS bit),CAST(COALESCE(MAX(CAST([Failed] AS int)),0) AS bit) FROM " + Quote(name) + ";", 5, cancellation); + if (state == null || state.Length != 6) throw new InvalidOperationException("LobStateUnavailable"); + for (int i = 0; i < state.Length; i++) if (Missing(state[i])) throw new InvalidOperationException("LobStateUnavailable"); + return new MssqlImportLobState(Convert.ToBoolean(state[0], CultureInfo.InvariantCulture), Convert.ToInt64(state[1], CultureInfo.InvariantCulture), + Convert.ToInt64(state[2], CultureInfo.InvariantCulture), Convert.ToInt64(state[3], CultureInfo.InvariantCulture), + Convert.ToBoolean(state[4], CultureInfo.InvariantCulture), Convert.ToBoolean(state[5], CultureInfo.InvariantCulture)); + } + + public void ExecuteBatch(MssqlImportBatch batch, CancellationToken cancellation) + { + if (batch == null) throw new ArgumentNullException(nameof(batch)); + WithReader(batch.Text, 0, cancellation, reader => { Drain(reader, cancellation); return true; }); + } + + public MssqlImportCounts CountTargetRows(Action progress, CancellationToken cancellation) + { + var target = ReadTarget(cancellation); + if (!target.MetadataVisible) throw new InvalidOperationException("TargetMetadataIncomplete"); + int after = 0; long tables = 0, rows = 0; + while (true) + { + cancellation.ThrowIfCancellationRequested(); + // Keyset lookup closes before COUNT_BIG, so MARS is unnecessary and no catalog list grows in memory. + object[] table = ReadValues("SELECT TOP(1) t.object_id,s.name,t.name FROM sys.tables AS t JOIN sys.schemas AS s ON s.schema_id=t.schema_id " + + "WHERE t.is_ms_shipped=0 AND t.object_id>" + after.ToString(CultureInfo.InvariantCulture) + " ORDER BY t.object_id;", 5, cancellation); + if (table == null) break; + if (table.Length != 3 || Missing(table[0]) || Missing(table[1]) || Missing(table[2])) throw new InvalidOperationException("TargetTableUnavailable"); + int next = Convert.ToInt32(table[0], CultureInfo.InvariantCulture); + if (next <= after) throw new InvalidOperationException("TargetTableOrderInvalid"); + object actual = Scalar("SELECT COUNT_BIG(*) FROM " + Quote(Convert.ToString(table[1], CultureInfo.InvariantCulture)) + "." + + Quote(Convert.ToString(table[2], CultureInfo.InvariantCulture)) + ";", 0, cancellation); + if (Missing(actual)) throw new InvalidOperationException("TargetCountUnavailable"); + long count = Convert.ToInt64(actual, CultureInfo.InvariantCulture); + if (count < 0) throw new InvalidOperationException("TargetCountUnavailable"); + rows = checked(rows + count); tables = checked(tables + 1); after = next; + if (progress != null) progress(tables, rows); + } + return new MssqlImportCounts(tables, rows); + } + + public void CancelActiveCommand() + { + ActiveCommand command; + lock (gate) command = active; + if (command != null) RequestCancellation(command); + } + + private void RequestCancellation(ActiveCommand command) + { + lock (gate) + { + if (active != command || command.CancellationRequested) return; + command.CancellationRequested = true; + command.Watchdog = new Timer(_ => ReleaseOwner(command), null, cancelMilliseconds, Timeout.Infinite); + } + try { command.Command.Cancel(); } catch { /* Completion/disposal can win this exact command's race. */ } + } + + public MssqlImportCleanup Cleanup() + { + lock (gate) + { + if (cleanup != null) return cleanup; + if (active != null) return new MssqlImportCleanup(false, sessionReleased, false, "CommandStillActive"); + if (cleanupRunning) return new MssqlImportCleanup(false, sessionReleased, false, "CleanupStillActive"); + cleanupRunning = true; + } + bool transactionConfirmed = false; + string issue = null; + try + { + if (!ConnectionUsable()) issue = "SessionUnavailable"; + else + { + object[] state = ReadValues("IF @@TRANCOUNT>0 ROLLBACK TRANSACTION; SELECT @@TRANCOUNT,XACT_STATE();", 10, CancellationToken.None, true); + transactionConfirmed = state != null && state.Length == 2 && !Missing(state[0]) && !Missing(state[1]) && + Convert.ToInt32(state[0], CultureInfo.InvariantCulture) == 0 && Convert.ToInt32(state[1], CultureInfo.InvariantCulture) == 0; + if (!transactionConfirmed) issue = "TransactionCleanupUnconfirmed"; + } + } + catch { issue = "TransactionCleanupFailed"; } + finally { ReleaseOwner(null); } + lock (gate) + { + if (!sessionReleased) issue = issue == null ? "SessionReleaseFailed" : issue + ";SessionReleaseFailed"; + cleanup = new MssqlImportCleanup(active == null, sessionReleased, transactionConfirmed, issue); + cleanupRunning = false; + return cleanup; + } + } + + public void Dispose() { ReleaseOwner(null); } + + private void ReleaseOwner(ActiveCommand requiredActive) + { + IDisposable value; + lock (gate) + { + if (requiredActive != null && active != requiredActive || releaseStarted) return; + // Latch release under the same gate as the generation check, before any later command can start. + releaseStarted = true; value = owner; owner = null; + } + bool released = false; + try { value.Dispose(); released = true; } catch { /* Cleanup's receipt must report failure rather than infer release. */ } + finally { lock (gate) sessionReleased = released; } + } + + private bool ConnectionUsable() + { + lock (gate) { if (releaseStarted) return false; } + try { return isOpen(); } catch { return false; } + } + + private void EnsureNoActiveCommand() + { + lock (gate) { if (active != null || cleanupRunning) throw new InvalidOperationException("ImportCommandAlreadyActive"); } + } + + private T WithReader(string sql, int timeout, CancellationToken cancellation, Func action, bool cleaning = false) + { + cancellation.ThrowIfCancellationRequested(); + ActiveCommand owned; + lock (gate) + { + if (active != null || cleanupRunning && !cleaning) throw new InvalidOperationException("ImportCommandAlreadyActive"); + if (releaseStarted) throw new ObjectDisposedException(nameof(MssqlImportSqlSession)); + DbCommand command = createCommand(); + try { command.CommandText = sql; command.CommandTimeout = timeout; owned = new ActiveCommand(command); active = owned; } + catch { command.Dispose(); throw; } + } + DbDataReader reader = null; + var errors = new List(); + Exception failure = null; bool uncertain = false; + T result = default(T); + try + { + owned.Registration = cancellation.Register(() => RequestCancellation(owned)); + reader = owned.Command.ExecuteReaderAsync(CommandBehavior.SequentialAccess, cancellation).GetAwaiter().GetResult(); + result = action(reader); + cancellation.ThrowIfCancellationRequested(); + } + catch (Exception error) { failure = error; AddErrors(error, errors, ref uncertain); } + finally + { + try { if (reader != null) reader.Dispose(); } + catch (Exception error) { if (failure == null) failure = error; AddErrors(error, errors, ref uncertain); } + try { owned.Command.Dispose(); } + catch (Exception error) { if (failure == null) failure = error; AddErrors(error, errors, ref uncertain); } + try { owned.Registration.Dispose(); } + finally + { + lock (gate) + { + if (owned.Watchdog != null) owned.Watchdog.Dispose(); + if (active == owned) active = null; + } + } + } + if (failure != null) + { + if (errors.Count != 0 || !(failure is OperationCanceledException) || !cancellation.IsCancellationRequested) + throw new MssqlImportBatchException(errors, uncertain || failure is OperationCanceledException || cancellation.IsCancellationRequested || !ConnectionUsable()); + ExceptionDispatchInfo.Capture(failure).Throw(); + } + cancellation.ThrowIfCancellationRequested(); + return result; + } + + private static void AddErrors(Exception error, List errors, ref bool uncertain) + { + var sql = error as SqlException; + if (sql == null) { if (!(error is OperationCanceledException)) uncertain = true; return; } + foreach (SqlError detail in sql.Errors) + { + errors.Add(new MssqlImportSqlError(detail.Number, detail.State, detail.Class, detail.LineNumber, detail.Message)); + if (detail.Number == -2 || detail.Number == 0 || detail.Number == 64 || detail.Number == 233 || + detail.Number == 10053 || detail.Number == 10054 || detail.Number == 10060 || detail.Class >= 20) uncertain = true; + } + } + + private object Scalar(string sql, int timeout, CancellationToken cancellation) + { + object[] values = ReadValues(sql, timeout, cancellation); + if (values == null || values.Length != 1) throw new InvalidOperationException("ProbeResultUnavailable"); + return values[0]; + } + + private object[] ReadValues(string sql, int timeout, CancellationToken cancellation, bool cleaning = false) + { + return WithReader(sql, timeout, cancellation, reader => + { + object[] values = null; + if (reader.ReadAsync(cancellation).GetAwaiter().GetResult()) + { + if (reader.FieldCount > 16) throw new InvalidOperationException("ProbeShapeInvalid"); + values = new object[reader.FieldCount]; + for (int i = 0; i < values.Length; i++) values[i] = reader.GetValue(i); + if (reader.ReadAsync(cancellation).GetAwaiter().GetResult()) throw new InvalidOperationException("ProbeRowCountInvalid"); + } + if (reader.NextResultAsync(cancellation).GetAwaiter().GetResult()) throw new InvalidOperationException("ProbeResultCountInvalid"); + return values; + }, cleaning); + } + + private static void Drain(DbDataReader reader, CancellationToken cancellation) + { + do { while (reader.ReadAsync(cancellation).GetAwaiter().GetResult()) { cancellation.ThrowIfCancellationRequested(); } } + while (reader.NextResultAsync(cancellation).GetAwaiter().GetResult()); + } + + private static bool Missing(object value) { return value == null || value == DBNull.Value; } + private static bool? Permission(object value) + { + if (Missing(value)) return null; + int permission = Convert.ToInt32(value, CultureInfo.InvariantCulture); + return permission == 1 ? true : permission == 0 ? (bool?)false : null; + } + private static string Quote(string identifier) { return "[" + identifier.Replace("]", "]]") + "]"; } + } +} diff --git a/mySQLPunk/mySQLPunk.csproj b/mySQLPunk/mySQLPunk.csproj index 77e1478..e721bd4 100644 --- a/mySQLPunk/mySQLPunk.csproj +++ b/mySQLPunk/mySQLPunk.csproj @@ -366,6 +366,7 @@ + diff --git a/tests/Run-SmokeTests.ps1 b/tests/Run-SmokeTests.ps1 index 70da1df..bf3839a 100644 --- a/tests/Run-SmokeTests.ps1 +++ b/tests/Run-SmokeTests.ps1 @@ -143,7 +143,7 @@ if (!(Test-Path -LiteralPath $mysqlConnector)) { /r:System.Core.dll ` /r:System.IO.Compression.dll ` /r:System.IO.Compression.FileSystem.dll ` - (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Parser.cs") $source $preferencesSource $schemaSyncSource $erModelSource (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Snapshot.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Schema.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.ViewReferences.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Properties.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Artifact.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Values.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Lob.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Routing.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.SnapshotIntegration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.CompatibilityIntegration.cs") + (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Parser.cs") $source $preferencesSource $schemaSyncSource $erModelSource (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Snapshot.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Schema.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.ViewReferences.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Properties.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Artifact.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Values.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Lob.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Routing.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.SnapshotIntegration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.CompatibilityIntegration.cs") if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/tests/SmokeTests.MssqlImport.Integration.cs b/tests/SmokeTests.MssqlImport.Integration.cs new file mode 100644 index 0000000..767089a --- /dev/null +++ b/tests/SmokeTests.MssqlImport.Integration.cs @@ -0,0 +1,317 @@ +using System; +using System.Collections.Generic; +using System.Collections; +using System.Data; +using System.Data.Common; +using System.Data.SqlClient; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using mySQLPunk.lib; +using mySQLPunk.lib.MssqlImport; +using mySQLPunk.lib.MssqlExport; + +public static partial class SmokeTests +{ + private static void MssqlImportConnectionOptions() + { + var settings = new Dictionary { + { "db_kind", "mssql" }, { "host", "fixture-server" }, { "port", "1433" }, + { "initial_database", "fixture-target" }, { "trusted_connection", "T" }, { "tls_mode", "Required" } + }; + var builder = new SqlConnectionStringBuilder(ConnectionConfigurationService.BuildMssqlImportConnectionString(settings)); + Assert(!builder.MultipleActiveResultSets && builder.ConnectRetryCount == 0, + "Import must disable MARS and reconnect before opening its owned connection."); + Assert(builder.InitialCatalog == "fixture-target" && builder.IntegratedSecurity && builder.Encrypt, + "Import keeps explicit target and existing authentication/TLS options."); + var old = new SqlConnectionStringBuilder(ConnectionConfigurationService.BuildSqlServerConnectionString(settings)); + Assert(old.MultipleActiveResultSets && old.ConnectRetryCount == 1, "Existing callers keep their original connection defaults."); + Assert((string)settings["initial_database"] == "fixture-target" && settings.Count == 6, "Builder does not mutate supplied settings."); + settings["initial_database"] = " "; + AssertThrows(() => ConnectionConfigurationService.BuildMssqlImportConnectionString(settings), "Missing target is refused before Open."); + AssertThrows(() => ConnectionOpenService.OpenMssqlImportSession(settings), "Invalid target does not open a provider or SSH tunnel."); + settings["db_kind"] = "mysql"; + AssertThrows(() => ConnectionOpenService.OpenMssqlImportSession(settings), "Importer refuses other engines."); + } + + private static readonly MssqlImportBatch ImportSessionBatch = new MssqlImportBatch(1, 0, 20, 1, 2, "SELECT 'original; GO';\r\n-- preserve\r\n"); + + private static void MssqlImportSessionDrainsResults() + { + var owner = new ImportSessionOwner(); + var reader = new ImportSessionReader(new[] { 200000, 0, 3 }, rejectValues: true); + var command = new ImportSessionCommand(reader); + using (var session = new MssqlImportSqlSession(owner, () => command, () => true)) { + session.ExecuteBatch(ImportSessionBatch, CancellationToken.None); + Assert(command.CommandText == ImportSessionBatch.Text && command.CommandTimeout == 0, "Original batch reaches SQL unchanged with timeout0."); + Assert(command.Behavior == CommandBehavior.SequentialAccess && reader.RowsRead == 200003 && reader.NextCalls == 3, + "Every row and result is drained sequentially without reading/materializing field values."); + Assert(reader.Disposes == 1 && command.Disposes == 1 && command.LastToken == CancellationToken.None, + "Completion includes reader and command disposal."); + } + Assert(owner.Disposes == 1, "Only the owned session is released."); + + foreach (string point in new[] { "start", "read", "next", "dispose" }) { + var failedReader = new ImportSessionReader(new[] { 1 }, rejectValues: true); + var failedCommand = new ImportSessionCommand(failedReader); + var primary = DiagnosticSql(547, 2627); + if (point == "start") failedCommand.StartError = primary; + if (point == "read") failedReader.ReadError = primary; + if (point == "next") failedReader.NextError = primary; + failedReader.DisposeError = point == "dispose" ? primary : DiagnosticSql(50001); + var failedOwner = new ImportSessionOwner(); + using (var session = new MssqlImportSqlSession(failedOwner, () => failedCommand, () => true)) { + try { session.ExecuteBatch(ImportSessionBatch, CancellationToken.None); throw new Exception("Expected SQL failure " + point); } + catch (MssqlImportBatchException e) { + Assert(e.Errors.Count == (point == "start" || point == "dispose" ? 2 : 3), "All SQL details survive " + point + " and reader disposal."); + Assert(e.Errors[0].Number == 547 && e.Errors[1].Number == 2627 && !e.OutcomeUncertain, + "Ordinary provider details preserve number/state/class/line without inventing uncertainty: " + point); + } + Assert(failedCommand.Disposes == 1, "Failed command releases once: " + point); + } + Assert(failedOwner.Disposes == 1, "Failure owns only its session: " + point); + } + var transport = new ImportSessionCommand(null) { StartError = new IOException("fixture transport failure") }; + using (var session = new MssqlImportSqlSession(new ImportSessionOwner(), () => transport, () => true)) { + try { session.ExecuteBatch(ImportSessionBatch, CancellationToken.None); throw new Exception("Expected transport failure"); } + catch (MssqlImportBatchException e) { Assert(e.OutcomeUncertain && e.Errors.Count == 0, "Transport failure is uncertain and cannot look like a skippable SQL error."); } + } + foreach (int code in new[] { -2, 0, 64, 233, 10053, 10054, 10060 }) { + var network = new ImportSessionCommand(null) { StartError = DiagnosticSql(code) }; + using (var session = new MssqlImportSqlSession(new ImportSessionOwner(), () => network, () => true)) { + try { session.ExecuteBatch(ImportSessionBatch, CancellationToken.None); throw new Exception("Expected network/timeout failure"); } + catch (MssqlImportBatchException e) { Assert(e.OutcomeUncertain && e.Errors.Count == 1, "Known timeout/transport codes cannot become ordinary skippable SQL errors: " + code); } + } + } + var unexpectedCancel = new ImportSessionCommand(null) { StartError = new OperationCanceledException() }; + using (var session = new MssqlImportSqlSession(new ImportSessionOwner(), () => unexpectedCancel, () => true)) + AssertThrows(() => session.ExecuteBatch(ImportSessionBatch, CancellationToken.None), "Provider cancellation without a caller request is uncertain, not user cancellation."); + } + + private static void MssqlImportSessionCancellationOwnership() + { + var owner = new ImportSessionOwner(); var tree = new ImportSessionOwner(); + var entered = new ManualResetEventSlim(); var release = new ManualResetEventSlim(); + var command = new ImportSessionCommand(new ImportSessionReader(new[] { 0 }, true)); + command.Start = (behavior, token) => { entered.Set(); release.Wait(); return Task.FromResult(command.Reader); }; + using (var cancel = new CancellationTokenSource()) using (var session = new MssqlImportSqlSession(owner, () => command, () => true, 40)) { + var task = Task.Run(() => { try { session.ExecuteBatch(ImportSessionBatch, cancel.Token); } catch (OperationCanceledException) { } }); + Assert(entered.Wait(2000), "Command startup enters active ownership."); + AssertThrows(() => session.ReadState(CancellationToken.None), "No state query can overlap active reader/startup."); + cancel.Cancel(); + Assert(command.Cancels > 0 && command.LastToken == cancel.Token, "Cancellation reaches the exact startup command and token."); + Assert(owner.Released.Wait(2000), "Watchdog attempts owned close after cancellation deadline."); + var pending = session.Cleanup(); + Assert(!pending.CommandEnded && pending.SessionReleased && !pending.TransactionCleanupConfirmed, + "Owned close is not command acknowledgement or rollback proof."); + release.Set(); Assert(task.Wait(2000), "Worker unwinds only after provider completion."); + var final = session.Cleanup(); + Assert(final.CommandEnded && final.SessionReleased && !final.TransactionCleanupConfirmed, "Unwound closed session still cannot prove rollback."); + Parallel.For(0, 20, i => session.Dispose()); + Assert(owner.Disposes == 1 && tree.Disposes == 0, "Cancel/cleanup/Dispose race releases this owner once and never the independent tree owner."); + } + entered.Dispose(); release.Dispose(); + + foreach (string phase in new[] { "read", "next", "read-sql", "dispose" }) { + using (var cancel = new CancellationTokenSource()) { + var readOwner = new ImportSessionOwner(); var reader = new ImportSessionReader(new[] { 1 }, true); + var reading = new ImportSessionCommand(reader); + if (phase == "dispose") reader.BeforeDispose = () => cancel.Cancel(); + else if (phase == "next") reader.BeforeNext = () => cancel.Cancel(); + else reader.BeforeRead = () => cancel.Cancel(); + if (phase == "read-sql") reader.ReadError = DiagnosticSql(547, 2627); + using (var session = new MssqlImportSqlSession(readOwner, () => reading, () => true)) { + try { session.ExecuteBatch(ImportSessionBatch, cancel.Token); throw new Exception("Expected cancellation during " + phase); } + catch (OperationCanceledException) { Assert(phase != "read-sql", "SQL details must not disappear behind cancellation."); } + catch (MssqlImportBatchException error) { Assert(phase == "read-sql" && error.OutcomeUncertain && error.Errors.Count == 2, "Cancellation retains all delivered SQL details before stopping."); } + Assert(reading.Cancels == 1 && reader.Disposes == 1 && reading.Disposes == 1, "Read/NextResult cancellation retains ownership until disposal: " + phase); + } + Assert(readOwner.Disposes == 1, "Read cancellation releases exact owner: " + phase); + } + } + var disposingOwner = new ImportSessionOwner(); + using (var disposeEntered = new ManualResetEventSlim()) using (var disposeRelease = new ManualResetEventSlim()) { + var reader = new ImportSessionReader(new[] { 0 }, true) { BeforeDispose = () => { disposeEntered.Set(); disposeRelease.Wait(); } }; + var cmd = new ImportSessionCommand(reader); + using (var session = new MssqlImportSqlSession(disposingOwner, () => cmd, () => true)) { + var task = Task.Run(() => session.ExecuteBatch(ImportSessionBatch, CancellationToken.None)); + Assert(disposeEntered.Wait(2000) && !task.IsCompleted, "Reader Dispose remains inside batch acknowledgement."); + AssertThrows(() => session.ReadState(CancellationToken.None), "A blocked reader Dispose still owns the command slot."); + Assert(!session.Cleanup().CommandEnded, "Cleanup cannot acknowledge an unfinished reader Dispose."); + disposeRelease.Set(); Assert(task.Wait(2000), "Batch acknowledgement follows actual Dispose completion."); + } + } + + var lateOwner = new ImportSessionOwner(); var commands = new Queue(); + var first = new ImportSessionCommand(new ImportSessionReader(new[] { 0 }, true)); + first.Start = (behavior, token) => { token.ThrowIfCancellationRequested(); return Task.FromResult(first.Reader); }; + var second = new ImportSessionCommand(new ImportSessionReader(new[] { 0 }, true)); + var secondEntered = new ManualResetEventSlim(); var secondRelease = new ManualResetEventSlim(); + second.Start = (behavior, token) => { secondEntered.Set(); secondRelease.Wait(); return Task.FromResult(second.Reader); }; + commands.Enqueue(first); commands.Enqueue(second); + using (var session = new MssqlImportSqlSession(lateOwner, () => commands.Dequeue(), () => true, 50)) { + first.Reader.BeforeRead = () => session.CancelActiveCommand(); + session.ExecuteBatch(ImportSessionBatch, CancellationToken.None); + var later = Task.Run(() => session.ExecuteBatch(ImportSessionBatch, CancellationToken.None)); + Assert(secondEntered.Wait(2000) && !lateOwner.Released.Wait(100), "A completed command's cancellation timer cannot close an active later generation."); + secondRelease.Set(); Assert(later.Wait(2000), "Later generation completes normally."); + } + secondEntered.Dispose(); secondRelease.Dispose(); + Assert(lateOwner.Disposes == 1, "Normal disposal releases the surviving owner."); + var invalidOwner = new ImportSessionOwner(); + AssertThrows(() => new MssqlImportSqlSession(invalidOwner, null, () => true), "Initialization failure releases transferred lifetime ownership."); + Assert(invalidOwner.Disposes == 1, "Failed initialization releases exactly once."); + + var closedConnection = new SqlConnection(); + var provider = new FakeExecDatabase("mssql", "0"); + using (var real = new MssqlImportSqlSession(new MssqlOwnedSession(provider, closedConnection))) { + AssertThrows(() => real.ExecuteBatch(ImportSessionBatch, CancellationToken.None), "Real closed SQL connection startup fails, without opening a database."); + } + closedConnection.Dispose(); + } + + private static ImportSessionReader ImportValues(params object[] row) { return new ImportSessionReader(new[] { new[] { row } }); } + private static object[] ImportIdentity(int user = 5, object viewDefinition = null, string version = "15.0.2000.5") + { return new object[] { "fixture-server", "fixture", 7, new DateTime(2026, 10, 13), version, "READ_WRITE", user, viewDefinition ?? 1, 0, 0 }; } + + private static void MssqlImportSessionMetadataProof() + { + foreach (string mode in new[] { "dbo", "no-deny", "deny", "low", "null", "2022-no-security", "2022-security", "denied-scan", "count-failure" }) { + var owner = new ImportSessionOwner(); var issued = new List(); + var identity = ImportIdentity(mode == "dbo" ? 1 : 5, mode == "low" ? (object)0 : mode == "null" ? DBNull.Value : 1, mode.StartsWith("2022") ? "16.0.1" : "15.0.1"); + var queue = new Queue(); queue.Enqueue(ImportValues(identity)); + if (mode.StartsWith("2022")) queue.Enqueue(ImportValues(mode == "2022-security" ? 1 : 0)); + if (mode != "dbo" && mode != "low" && mode != "null" && mode != "2022-no-security") queue.Enqueue(ImportValues(mode == "deny" ? 1L : 0L)); + bool complete = mode == "dbo" || mode == "no-deny" || mode == "2022-security"; + if (complete || mode == "count-failure") queue.Enqueue(ImportValues(0L)); + using (var session = new MssqlImportSqlSession(owner, () => { + var cmd = new ImportSessionCommand(queue.Dequeue()); issued.Add(cmd); + if (mode == "denied-scan" && issued.Count == 2 || mode == "count-failure" && issued.Count == 3) cmd.StartError = DiagnosticSql(229); + return cmd; + }, () => true)) { + var target = session.ReadTarget(CancellationToken.None); + Assert(target.DatabaseId == 7 && target.DatabaseName == "fixture" && target.Writable && !target.CanCreateTable.Value, + "Actual identity/writeability/create capability are independent: " + mode); + Assert(target.MetadataVisible == complete && target.UserObjectCount == (complete ? (long?)0 : null), + "Only proven complete metadata yields empty0; unknown remains null: " + mode); + Assert(issued.All(c => c.CommandTimeout == 5 && c.Disposes == 1), "Read-only metadata probes use5sec and dispose before another: " + mode); + var denyQuery = issued.Select(c => c.CommandText).FirstOrDefault(sql => sql.Contains("sys.database_permissions")); + if (denyQuery != null) Assert(denyQuery.Contains("sys.user_token") && !denyQuery.Contains("sys.objects"), "Effective-token DENY scan cannot hide rows via object-catalog join."); + } + } + foreach (int column in new[] { 0, 1, 2, 3, 4 }) { + var identity = ImportIdentity(); identity[column] = DBNull.Value; + using (var session = new MssqlImportSqlSession(new ImportSessionOwner(), () => new ImportSessionCommand(ImportValues(identity)), () => true)) + AssertThrows(() => session.ReadTarget(CancellationToken.None), "Missing target identity is a failed probe, never synthesized."); + } + } + + private static void MssqlImportSessionProbesAndCleanup() + { + var owner = new ImportSessionOwner(); var commands = new List(); + var readers = new Queue(new[] { ImportValues(7, 0, 0), ImportValues(true, 1L, 9L, 9L, true, false), ImportValues(0, 0) }); + using (var session = new MssqlImportSqlSession(owner, () => { var cmd = new ImportSessionCommand(readers.Dequeue()); commands.Add(cmd); return cmd; }, () => true)) { + var state = session.ReadState(CancellationToken.None); Assert(state.IsOpen && state.DatabaseId == 7 && state.TransactionCount == 0 && state.XactState == 0, "State keeps DB and transaction facts."); + var job = new Guid("10000000-0000-0000-0000-000000000001"); var lob = session.ReadLobState(job, CancellationToken.None); + Assert(lob.Exists && lob.RowCount == 1 && lob.Sequence == 9 && lob.ConsumedThrough == 9 && lob.Consumed && !lob.Failed, "LOB aggregate preserves unique row and protocol counters."); + Assert(commands[1].CommandText.Contains("#mp_" + job.ToString("N") + "_s") && commands[1].CommandTimeout == 5, "LOB lookup uses only GUID-derived identifier and bounded timeout."); + var result = session.Cleanup(); + Assert(result.CommandEnded && result.SessionReleased && result.TransactionCleanupConfirmed && result.IssueCode == null, "Only returned zero transaction state and released owner confirm cleanup."); + Assert(commands[2].CommandTimeout == 10 && commands[2].LastToken == CancellationToken.None && commands[2].CommandText.Contains("ROLLBACK"), "Cleanup is independent10sec with uncancelled token."); + Assert(object.ReferenceEquals(result, session.Cleanup()) && commands.Count == 3 && owner.Disposes == 1, "Repeated cleanup returns actual cached receipt without another query or release."); + } + foreach (string failure in new[] { "closed", "rollback", "release" }) { + var failedOwner = new ImportSessionOwner { Error = failure == "release" ? new IOException("fixture release") : null }; + var cmd = new ImportSessionCommand(ImportValues(0, 0)) { StartError = failure == "rollback" ? DiagnosticSql(-2) : null }; + using (var session = new MssqlImportSqlSession(failedOwner, () => cmd, () => failure != "closed")) { + var result = session.Cleanup(); + Assert(result.CommandEnded && result.SessionReleased == (failure != "release") && result.TransactionCleanupConfirmed == (failure == "release") && result.IssueCode != null, + "Cleanup distinguishes actual rollback and resource-release evidence: " + failure); + } + } + + var countCommands = new List(); + var rows = new Queue(new[] { ImportValues(ImportIdentity(1)), ImportValues(2L), ImportValues(10, "schema]x", "table]x"), ImportValues(3000000000L), ImportValues(11, "dbo", "t2"), ImportValues(4L), new ImportSessionReader(new object[][][] { new object[0][] }) }); + using (var session = new MssqlImportSqlSession(new ImportSessionOwner(), () => { var cmd = new ImportSessionCommand(rows.Dequeue()); countCommands.Add(cmd); return cmd; }, () => true)) { + long progressTables = 0, progressRows = 0; + var counts = session.CountTargetRows((tables, total) => { progressTables = tables; progressRows = total; }, CancellationToken.None); + Assert(counts.Tables == 2 && counts.Rows == 3000000004L && progressTables == 2 && progressRows == counts.Rows, "COUNT_BIG totals and callbacks retain Int64 actual results."); + Assert(countCommands.Any(c => c.CommandText.Contains("[schema]]x].[table]]x]")), "Every catalog identifier is bracket quoted."); + Assert(countCommands.Where(c => c.CommandText.Contains("COUNT_BIG(*) FROM [")).All(c => c.CommandTimeout == 0), "Long row counts remain cancellable without a default timeout."); + } + } + + private sealed class ImportSessionOwner : IDisposable + { + internal int Disposes; internal Exception Error; internal ManualResetEventSlim Released = new ManualResetEventSlim(); + public void Dispose() { Interlocked.Increment(ref Disposes); Released.Set(); if (Error != null) throw Error; } + } + private sealed class ImportSessionCommand : DbCommand + { + internal ImportSessionReader Reader; internal Exception StartError; internal Func> Start; + internal CommandBehavior Behavior; internal CancellationToken LastToken; internal int Cancels, Disposes; + internal ImportSessionCommand(ImportSessionReader reader) { Reader = reader; } + public override string CommandText { get; set; } + public override int CommandTimeout { get; set; } + public override CommandType CommandType { get; set; } + public override UpdateRowSource UpdatedRowSource { get; set; } + public override bool DesignTimeVisible { get; set; } + protected override DbConnection DbConnection { get; set; } + protected override DbTransaction DbTransaction { get; set; } + protected override DbParameterCollection DbParameterCollection { get { throw new NotSupportedException(); } } + protected override DbParameter CreateDbParameter() { throw new NotSupportedException(); } + public override void Cancel() { Interlocked.Increment(ref Cancels); } + public override void Prepare() { throw new NotSupportedException(); } + public override int ExecuteNonQuery() { throw new Exception("ExecuteNonQuery would skip result-drain acknowledgement"); } + public override object ExecuteScalar() { throw new NotSupportedException(); } + protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) { throw new Exception("Startup must use async cancellation token"); } + protected override Task ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken token) + { Behavior = behavior; LastToken = token; if (StartError != null) throw StartError; return Start != null ? Start(behavior, token) : Task.FromResult(Reader); } + protected override void Dispose(bool disposing) { if (disposing) Disposes++; base.Dispose(disposing); } + } + private sealed class ImportSessionReader : DbDataReader + { + private readonly int[] rowCounts; private readonly object[][][] values; private readonly bool rejectValues; + private int result, row = -1; + internal long RowsRead; internal int NextCalls, Disposes; internal Exception ReadError, NextError, DisposeError; internal Action BeforeRead, BeforeNext, BeforeDispose; + internal ImportSessionReader(int[] rowCounts, bool rejectValues) { this.rowCounts = rowCounts; this.rejectValues = rejectValues; } + internal ImportSessionReader(object[][][] values) { this.values = values; rowCounts = values.Select(x => x.Length).ToArray(); } + public override bool Read() { if (BeforeRead != null) { var action = BeforeRead; BeforeRead = null; action(); } if (ReadError != null) throw ReadError; bool found = ++row < rowCounts[result]; if (found) RowsRead++; return found; } + public override bool NextResult() { NextCalls++; if (BeforeNext != null) { var action = BeforeNext; BeforeNext = null; action(); } if (NextError != null) throw NextError; if (result + 1 >= rowCounts.Length) return false; result++; row = -1; return true; } + public override Task ReadAsync(CancellationToken token) { token.ThrowIfCancellationRequested(); return Task.FromResult(Read()); } + public override Task NextResultAsync(CancellationToken token) { token.ThrowIfCancellationRequested(); return Task.FromResult(NextResult()); } + public override int FieldCount { get { return values == null || values[result].Length == 0 ? 0 : values[result][0].Length; } } + public override object GetValue(int ordinal) { if (rejectValues) throw new Exception("Drain must not materialize LOB or field values"); return values[result][row][ordinal]; } + public override bool IsDBNull(int ordinal) { return GetValue(ordinal) == DBNull.Value; } + public override string GetString(int ordinal) { return (string)GetValue(ordinal); } + public override int GetInt32(int ordinal) { return Convert.ToInt32(GetValue(ordinal)); } + public override long GetInt64(int ordinal) { return Convert.ToInt64(GetValue(ordinal)); } + public override bool GetBoolean(int ordinal) { return Convert.ToBoolean(GetValue(ordinal)); } + public override DateTime GetDateTime(int ordinal) { return (DateTime)GetValue(ordinal); } + public override object this[int ordinal] { get { return GetValue(ordinal); } } + public override object this[string name] { get { throw new NotSupportedException(); } } + public override int Depth { get { return 0; } } + public override bool HasRows { get { return rowCounts[result] > 0; } } + public override bool IsClosed { get { return Disposes > 0; } } + public override int RecordsAffected { get { throw new Exception("Affected rows are not imported rows"); } } + public override void Close() { } + protected override void Dispose(bool disposing) { if (disposing) { if (BeforeDispose != null) BeforeDispose(); Disposes++; if (DisposeError != null) throw DisposeError; } } + public override string GetName(int ordinal) { return ordinal.ToString(); } + public override int GetOrdinal(string name) { throw new NotSupportedException(); } + public override string GetDataTypeName(int ordinal) { throw new NotSupportedException(); } + public override Type GetFieldType(int ordinal) { throw new NotSupportedException(); } + public override int GetValues(object[] buffer) { throw new NotSupportedException(); } + public override byte GetByte(int ordinal) { throw new NotSupportedException(); } + public override long GetBytes(int ordinal, long offset, byte[] buffer, int bufferOffset, int length) { throw new Exception("LOB getter forbidden in drain"); } + public override char GetChar(int ordinal) { throw new NotSupportedException(); } + public override long GetChars(int ordinal, long offset, char[] buffer, int bufferOffset, int length) { throw new Exception("LOB getter forbidden in drain"); } + public override Guid GetGuid(int ordinal) { throw new NotSupportedException(); } + public override short GetInt16(int ordinal) { throw new NotSupportedException(); } + public override float GetFloat(int ordinal) { throw new NotSupportedException(); } + public override double GetDouble(int ordinal) { throw new NotSupportedException(); } + public override decimal GetDecimal(int ordinal) { throw new NotSupportedException(); } + public override IEnumerator GetEnumerator() { throw new NotSupportedException(); } + } +} diff --git a/tests/SmokeTests.cs b/tests/SmokeTests.cs index 1d474d4..ac0dd7b 100644 --- a/tests/SmokeTests.cs +++ b/tests/SmokeTests.cs @@ -31,6 +31,11 @@ public static int Main(string[] args) if (args.Length != 0) return SnapshotCrashChild(args); if (Environment.GetEnvironmentVariable("MYSQLPUNK_MSSQL_WIZARD_PREVIEW") == "1") return WizardPreview(); int passed = 0; + Run("MSSQL import worker session options", MssqlImportConnectionOptions, ref passed); + Run("MSSQL import worker session drain", MssqlImportSessionDrainsResults, ref passed); + Run("MSSQL import worker session cancellation", MssqlImportSessionCancellationOwnership, ref passed); + Run("MSSQL import worker session metadata", MssqlImportSessionMetadataProof, ref passed); + Run("MSSQL import worker session probes", MssqlImportSessionProbesAndCleanup, ref passed); Run("MSSQL import worker log faults", MssqlImportLogFaultsPropagate, ref passed); Run("MSSQL import worker window and throttle", MssqlImportProgressWindowAndThrottle, ref passed); Run("MSSQL import worker tail bound", MssqlImportLogTailIsBounded, ref passed); From 64416e0cccffaa5fbb25ab96b69f163a2ebb5e88 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 22:25:27 +0800 Subject: [PATCH 11/26] docs: record owned import session acceptance --- docs/design/mssql-import/implementation-plan.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/design/mssql-import/implementation-plan.md b/docs/design/mssql-import/implementation-plan.md index 3d932af..aebc04b 100644 --- a/docs/design/mssql-import/implementation-plan.md +++ b/docs/design/mssql-import/implementation-plan.md @@ -10,7 +10,7 @@ **Spec:** [design.md](design.md),使用者於 2026-10-13 回覆「好,進實作」核准書面規格。 -**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 已實作與覆核通過(0982548/3ebf6b3,修正兩項 P2);Task2 log/ETA 已實作與覆核通過(0cc1657);Task3 開始。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 +**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 已實作與覆核通過(0982548/3ebf6b3,修正兩項 P2);Task2 log/ETA 已實作與覆核通過(0cc1657);Task3 專用連線層已實作與覆核通過(9df6437);Task4 開始。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 **Execution:** 保留先前選定的「分工實作並逐項覆核」。一次一位 implementer,各 task 經獨立覆核後才接下一項;最後整體覆核。build、native UI 與 DB tests 由單一 owner 串行執行,避免共享輸出/fixture 衝突。 @@ -110,11 +110,11 @@ **Interfaces:** `ConnectionOpenService.OpenMssqlImportSession(Dictionary): MssqlOwnedSession`,在開線前套 `ConnectRetryCount=0`、`MultipleActiveResultSets=false`;原 `OpenMssqlSession` 行為維持。`MssqlImportSqlSession(MssqlOwnedSession)` implements IMssqlImportSession,owner 只釋放一次。 -- [ ] **Step 1: 加入失敗 tests。** importer builder 明確 Initial Catalog/retry0/MARS false;舊 caller 既有值不變。使用 fake owner 驗證取消、初始化失敗、Dispose race 只有本次 session/SSH lease 被釋放,樹 provider 不受影響。 -- [ ] **Step 2: 實作唯讀 target/state/LOB probes。** server/DB id/create_date/版本/writable/metadata 可見性/object count;必要能力不以 sysadmin 或 ALTER DATABASE 一票否決。NativeSchema 非空/無法確認空庫擋下;Generic/NativeData 不套空庫要求。所有 identifiers quote,LOB temp name 只由 Guid.ToString("N") 組成;state query 5秒,lookup 不能讀任意帳號設定。 -- [ ] **Step 3: 實作原文 ExecuteReader 與所有 result drain。** `CommandBehavior.SequentialAccess`,涵蓋 ExecuteReader/Read/NextResult/reader Dispose 的全部 SqlError;不建 DataTable/回傳資料集合。CommandTimeout0,token+Cancel 包住啟動與後續讀取,保留目前 command 的可靠 ownership。 -- [ ] **Step 4: 實作及測 cancellation/cleanup seam。** 不在 active reader 尚在跑時發第二條 status query;cleanup 獨立10秒,不使用已取消 token;關閉本 owner 不宣稱 rollback 已完成。一般 GO 跨 session 測 temp/SET/identity/transaction;另測 @@ROWCOUNT/@@ERROR 邊界並更新 generic-script 說明,避免不實相容宣稱。 -- [ ] **Step 5: 跑 worker/parser filters,提交。** native live cases 暫列 Task6 執行,不能以 fake 通過冒稱 DB 通過。Commit `feat: add isolated MSSQL import session adapter`。 +- [x] **Step 1: 加入失敗 tests。** importer builder 明確 Initial Catalog/retry0/MARS false;舊 caller 既有值不變。使用 fake owner 驗證取消、初始化失敗、Dispose race 只有本次 session/SSH lease 被釋放,樹 provider 不受影響。 +- [x] **Step 2: 實作唯讀 target/state/LOB probes。** server/DB id/create_date/版本/writable/metadata 可見性/object count;必要能力不以 sysadmin 或 ALTER DATABASE 一票否決。NativeSchema 非空/無法確認空庫擋下;Generic/NativeData 不套空庫要求。所有 identifiers quote,LOB temp name 只由 Guid.ToString("N") 組成;state query 5秒,lookup 不能讀任意帳號設定。 +- [x] **Step 3: 實作原文 ExecuteReader 與所有 result drain。** `CommandBehavior.SequentialAccess`,涵蓋 ExecuteReader/Read/NextResult/reader Dispose 的全部 SqlError;不建 DataTable/回傳資料集合。CommandTimeout0,token+Cancel 包住啟動與後續讀取,保留目前 command 的可靠 ownership。 +- [x] **Step 4: 實作及測 cancellation/cleanup seam。** 不在 active reader 尚在跑時發第二條 status query;cleanup 獨立10秒,不使用已取消 token;關閉本 owner 不宣稱 rollback 已完成。一般 GO 跨 session 測 temp/SET/identity/transaction;另測 @@ROWCOUNT/@@ERROR 邊界並更新 generic-script 說明,避免不實相容宣稱。 +- [x] **Step 5: 跑 worker/parser filters,提交。** native live cases 暫列 Task6 執行,不能以 fake 通過冒稱 DB 通過。Commit `feat: add isolated MSSQL import session adapter`。 ## Task 4: Sequential worker、recoverable skip、EOF checks 與取消結果 From 0707bc9a1d08672042d5656a66ca4919042e560c Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 22:39:44 +0800 Subject: [PATCH 12/26] feat: execute MSSQL import batches with explicit outcomes --- mySQLPunk/lib/MssqlImport/MssqlImportLog.cs | 2 +- .../MssqlImport/MssqlImportScriptInspector.cs | 16 +- .../lib/MssqlImport/MssqlImportService.cs | 369 ++++++++++++++++++ mySQLPunk/mySQLPunk.csproj | 1 + tests/SmokeTests.MssqlImport.Worker.cs | 324 +++++++++++++++ tests/SmokeTests.cs | 7 + 6 files changed, 717 insertions(+), 2 deletions(-) create mode 100644 mySQLPunk/lib/MssqlImport/MssqlImportService.cs diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportLog.cs b/mySQLPunk/lib/MssqlImport/MssqlImportLog.cs index f42daaa..8117034 100644 --- a/mySQLPunk/lib/MssqlImport/MssqlImportLog.cs +++ b/mySQLPunk/lib/MssqlImport/MssqlImportLog.cs @@ -104,7 +104,7 @@ private static IEnumerable ErrorParts(MssqlImportBatch batch, MssqlImpor " OutcomeUncertain=" + error.OutcomeUncertain + " Action=" + action + "\r\n"; foreach (var detail in error.Errors) { - long? sourceLine = detail.RelativeLine > 0 && batch.StartLine <= long.MaxValue - detail.RelativeLine + 1 + long? sourceLine = batch.StartLine > 0 && detail.RelativeLine > 0 && batch.StartLine <= long.MaxValue - detail.RelativeLine + 1 ? (long?)(batch.StartLine + ((long)detail.RelativeLine - 1)) : null; yield return "Number=" + detail.Number.ToString(CultureInfo.InvariantCulture) + " State=" + detail.State.ToString(CultureInfo.InvariantCulture) + " Class=" + detail.Class.ToString(CultureInfo.InvariantCulture) + " RelativeLine=" + detail.RelativeLine.ToString(CultureInfo.InvariantCulture) + diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs b/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs index e0cd69c..2c03f10 100644 --- a/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs +++ b/mySQLPunk/lib/MssqlImport/MssqlImportScriptInspector.cs @@ -18,12 +18,16 @@ internal sealed class MssqlImportScriptInspector private MssqlImportBatch current; private int currentIndex; private bool complete; + internal bool UsesNativeLob { get; private set; } + internal bool InitializesNativeLob { get; private set; } + internal MssqlImportPhase Phase { get; private set; } internal MssqlImportScriptInspector(string databaseName = null) { this.databaseName = databaseName; } internal void Observe(MssqlImportBatch batch) { if (complete) throw new InvalidOperationException("Inspector is complete."); current = batch ?? throw new ArgumentNullException(nameof(batch)); + UsesNativeLob = false; InitializesNativeLob = false; Phase = MssqlImportPhase.None; string text = batch.Text; bool lineHasCode = false; int i = 0; @@ -135,16 +139,26 @@ private void Token(string token, bool quoted) return; } if (!quoted && token.Equals("USE", StringComparison.OrdinalIgnoreCase)) { usePending = true; return; } - if (!quoted && token.StartsWith("#mp_", StringComparison.OrdinalIgnoreCase)) + if ((!quoted || header) && token.StartsWith("#mp_", StringComparison.OrdinalIgnoreCase)) { candidate = true; lob = true; Guid parsed; if (token.Length != 38 || token[36] != '_' || (token[37] != 's' && token[37] != 'v' && token[37] != 'c') || !Guid.TryParseExact(token.Substring(4, 32), "N", out parsed) || parsed == Guid.Empty) throw Error("NativeFormat"); if (lobJob.HasValue && lobJob != parsed) throw Error("NativeFormat"); lobJob = parsed; + UsesNativeLob = true; + if (createKind == "object" && token[37] == 's') InitializesNativeLob = true; createKind = null; return; } + if (!quoted) + { + if (token.Equals("CONSTRAINT", StringComparison.OrdinalIgnoreCase) || token.Equals("FOREIGN", StringComparison.OrdinalIgnoreCase)) Phase = MssqlImportPhase.Constraints; + else if (createKind == "create" && token.Equals("INDEX", StringComparison.OrdinalIgnoreCase) && Phase != MssqlImportPhase.Constraints) Phase = MssqlImportPhase.Indexes; + else if (Phase == MssqlImportPhase.None && token.Equals("CREATE", StringComparison.OrdinalIgnoreCase)) Phase = MssqlImportPhase.Schema; + else if ((Phase == MssqlImportPhase.None || Phase == MssqlImportPhase.Schema) && (token.Equals("INSERT", StringComparison.OrdinalIgnoreCase) || token.Equals("UPDATE", StringComparison.OrdinalIgnoreCase) || token.Equals("DELETE", StringComparison.OrdinalIgnoreCase))) Phase = MssqlImportPhase.Data; + if (createKind == "create" && (token.Equals("UNIQUE", StringComparison.OrdinalIgnoreCase) || token.Equals("CLUSTERED", StringComparison.OrdinalIgnoreCase) || token.Equals("NONCLUSTERED", StringComparison.OrdinalIgnoreCase))) return; + } if (createKind == "object") { if (!token.StartsWith("#", StringComparison.Ordinal)) schema = true; diff --git a/mySQLPunk/lib/MssqlImport/MssqlImportService.cs b/mySQLPunk/lib/MssqlImport/MssqlImportService.cs new file mode 100644 index 0000000..1f2a0ad --- /dev/null +++ b/mySQLPunk/lib/MssqlImport/MssqlImportService.cs @@ -0,0 +1,369 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading; + +namespace mySQLPunk.lib.MssqlImport +{ + internal sealed class MssqlImportIssue + { + public string Code { get; } + public string Message { get; } + public bool IsWarning { get; } + public long BatchNumber { get; } + public long Line { get; } + public long ByteOffset { get; } + internal MssqlImportIssue(string code, bool warning = false, long batch = 0, long line = 0, long offset = 0) + { Code = code; Message = code; IsWarning = warning; BatchNumber = batch; Line = line; ByteOffset = offset; } + } + + // Resource ownership transfers exactly once; a stale wizard Dispose cannot close a running input/log. + internal sealed class MssqlImportPreflight : IDisposable + { + private readonly object gate = new object(); + private readonly MssqlImportService service; + private readonly MssqlImportRequest request; + private readonly string source; + private MssqlImportInput input; + private IMssqlImportLog log; + private bool claimed, disposed; + public bool Passed { get; } + public MssqlImportScan Scan { get; } + public MssqlImportTarget Target { get; } + public string LogPath { get; } + public IReadOnlyList Issues { get; } + internal MssqlImportPreflight(MssqlImportService service, MssqlImportRequest request, string source, MssqlImportInput input, + MssqlImportScan scan, MssqlImportTarget target, IMssqlImportLog log, IEnumerable issues) + { + this.service = service; this.request = request; this.source = source; this.input = input; this.log = log; + Scan = scan; Target = target; LogPath = log == null ? null : log.Path; + Issues = Array.AsReadOnly(issues.ToArray()); Passed = !Issues.Any(i => !i.IsWarning); + } + internal bool Claim(MssqlImportService caller, MssqlImportRequest current, out MssqlImportInput ownedInput, out IMssqlImportLog ownedLog) + { + ownedInput = null; ownedLog = null; + lock (gate) + { + if (disposed || claimed || !Passed || caller != service || current == null || request == null || + current.JobId != request.JobId || current.SkipSqlErrors != request.SkipSqlErrors || + !string.Equals(current.DatabaseName, request.DatabaseName, StringComparison.Ordinal)) return false; + string path; try { path = Path.GetFullPath(current.SourcePath); } catch { return false; } + if (!string.Equals(path, source, StringComparison.OrdinalIgnoreCase)) return false; + claimed = true; ownedInput = input; ownedLog = log; input = null; log = null; return true; + } + } + public void Dispose() + { + MssqlImportInput ownedInput; IMssqlImportLog ownedLog; + lock (gate) { if (disposed) return; disposed = true; ownedInput = input; ownedLog = log; input = null; log = null; } + try { if (ownedInput != null) ownedInput.Dispose(); } finally { if (ownedLog != null) ownedLog.Dispose(); } + } + } + + internal sealed class MssqlImportService + { + private readonly Func openSession; + private readonly Func openLog; + internal MssqlImportService(Func openSession, Func openLog) + { this.openSession = openSession ?? throw new ArgumentNullException(nameof(openSession)); this.openLog = openLog ?? throw new ArgumentNullException(nameof(openLog)); } + + internal MssqlImportPreflight Preflight(MssqlImportRequest request, Action progress, CancellationToken cancellation) + { + var issues = new List(); + MssqlImportInput input = null; MssqlImportScan scan = null; MssqlImportTarget target = null; IMssqlImportLog log = null; + string source = null; + try + { + if (request == null || string.IsNullOrWhiteSpace(request.SourcePath)) throw new InvalidOperationException("SourceRequired"); + if (string.IsNullOrWhiteSpace(request.DatabaseName)) throw new InvalidOperationException("TargetRequired"); + cancellation.ThrowIfCancellationRequested(); source = Path.GetFullPath(request.SourcePath); + input = MssqlImportInput.Open(source, request.DatabaseName); + var clock = Stopwatch.StartNew(); var estimator = new MssqlImportProgressEstimator(); + scan = input.Scan(cancellation, bytes => { + var p = new MssqlImportProgress(request.JobId, 0, MssqlImportStage.Scanning, scannedBytes: bytes, elapsed: clock.Elapsed); + if (estimator.ShouldReport(p, DateTime.UtcNow)) Notify(progress, p); + }); + cancellation.ThrowIfCancellationRequested(); + using (var session = openSession()) target = session.ReadTarget(cancellation); + string gate = TargetGate(request, scan, target); + if (gate != null) throw new InvalidOperationException(gate); + if (scan.Script.Kind == MssqlImportScriptKind.Generic) issues.Add(new MssqlImportIssue("SessionIntrinsicsMayChange", true)); + if (scan.Script.Kind != MssqlImportScriptKind.NativeSchema && (!target.MetadataVisible || target.UserObjectCount != 0)) issues.Add(new MssqlImportIssue("TargetNotProvenEmpty", true)); + if (target.CanCreateView != true) issues.Add(new MssqlImportIssue("CreateViewNotProven", true)); + if (scan.Script.Kind != MssqlImportScriptKind.NativeSchema && target.CanCreateTable != true) issues.Add(new MssqlImportIssue("CreateTableNotProven", true)); + issues.Add(new MssqlImportIssue("PartialBatchWritesMayRemain", true)); + log = openLog(request.JobId); log.WriteStart(request, scan, target); + cancellation.ThrowIfCancellationRequested(); + } + catch (Exception error) + { + var parser = error as MssqlImportInputException; + string code = parser != null ? parser.Code : cancellation.IsCancellationRequested ? "Cancelled" : SafeCode(error, "PreflightFailed"); + issues.Add(new MssqlImportIssue(code, false, parser == null ? 0 : parser.BatchNumber, parser == null ? 0 : parser.Line, parser == null ? 0 : parser.ByteOffset)); + try { if (input != null) input.Dispose(); } catch { issues.Add(new MssqlImportIssue("InputReleaseFailed")); } + try { if (log != null) log.Dispose(); } catch { issues.Add(new MssqlImportIssue("LogIncomplete")); } + input = null; log = null; + } + return new MssqlImportPreflight(this, request, source, input, scan, target, log, issues); + } + + internal MssqlImportResult Run(MssqlImportRequest request, MssqlImportPreflight preflight, Action progress, CancellationToken cancellation) + { + MssqlImportInput input; IMssqlImportLog log; + if (preflight == null || !preflight.Claim(this, request, out input, out log)) + return new MssqlImportResult(request == null ? Guid.Empty : request.JobId, MssqlImportStatus.Failed, + preflight == null || preflight.Scan == null ? 0 : preflight.Scan.FileBytes, validationSummary: "PreflightInvalidOrConsumed"); + return new Worker(this, request, preflight, input, log, progress, cancellation).Run(); + } + + private static string TargetGate(MssqlImportRequest request, MssqlImportScan scan, MssqlImportTarget target) + { + if (target == null || string.IsNullOrWhiteSpace(target.ServerName) || string.IsNullOrWhiteSpace(target.Version) || + target.DatabaseId <= 0 || target.DatabaseCreateDate == default(DateTime) || !string.Equals(target.DatabaseName, request.DatabaseName, StringComparison.Ordinal)) return "TargetIdentityUnavailable"; + if (!target.Writable) return "TargetReadOnly"; + if (scan.Script.Kind == MssqlImportScriptKind.NativeSchema) + { + if (!target.MetadataVisible || !target.UserObjectCount.HasValue) return "TargetVisibilityRequired"; + if (target.UserObjectCount != 0) return "TargetNotEmpty"; + if (scan.Script.ExpectedTables > 0 && target.CanCreateTable != true) return "CreateTableRequired"; + } + return null; + } + private static bool SameTarget(MssqlImportTarget a, MssqlImportTarget b) + { return a != null && b != null && a.DatabaseId == b.DatabaseId && a.DatabaseCreateDate == b.DatabaseCreateDate && string.Equals(a.ServerName, b.ServerName, StringComparison.Ordinal) && string.Equals(a.DatabaseName, b.DatabaseName, StringComparison.Ordinal); } + private static void Notify(Action action, MssqlImportProgress progress) + { if (action != null) { try { action(progress); } catch { /* An observer cannot change import truth. */ } } } + private static string SafeCode(Exception error, string fallback) + { + // Only service-owned fixed codes may cross the UI boundary; provider/IO messages may contain secrets. + if (error is InvalidOperationException) + switch (error.Message) + { + case "SourceRequired": case "TargetRequired": case "TargetIdentityUnavailable": case "TargetReadOnly": + case "TargetVisibilityRequired": case "TargetNotEmpty": case "CreateTableRequired": + case "TargetChanged": case "SessionStateInvalid": case "LobStateInvalid": case "LobInitializationMissing": + case "EofTransactionOpen": case "DigestMismatch": case "SummaryMismatch": return error.Message; + } + return fallback; + } + + private sealed class Worker + { + private readonly MssqlImportService service; + private readonly MssqlImportRequest request; + private readonly MssqlImportPreflight preflight; + private readonly MssqlImportInput input; + private readonly IMssqlImportLog log; + private readonly Action observer; + private readonly CancellationToken cancellation; + private readonly Stopwatch clock = Stopwatch.StartNew(); + private readonly MssqlImportProgressEstimator estimator = new MssqlImportProgressEstimator(); + private readonly object reportGate = new object(); + private MssqlImportProgress latest; + private IMssqlImportSession session; + private MssqlImportBatch batch; + private MssqlImportPhase phase; + private long successfulBytes, skippedBytes, successes, failures, acknowledged, boundary; + private long? uncertain; + private bool lobInitialized, unacknowledgedExecution, finished, logIncomplete; + private MssqlImportCleanup cleanup; + private MssqlImportStatus status = MssqlImportStatus.Failed; + private string summary = "ExecutionNotStarted"; + internal Worker(MssqlImportService service, MssqlImportRequest request, MssqlImportPreflight preflight, MssqlImportInput input, + IMssqlImportLog log, Action observer, CancellationToken cancellation) + { this.service = service; this.request = request; this.preflight = preflight; this.input = input; this.log = log; this.observer = observer; this.cancellation = cancellation; } + + internal MssqlImportResult Run() + { + Publish(MssqlImportStage.Executing, true); + using (cancellation.Register(Stopping)) + { + try + { + cancellation.ThrowIfCancellationRequested(); session = service.openSession(); + var target = session.ReadTarget(cancellation); + if (!SameTarget(preflight.Target, target)) throw new InvalidOperationException("TargetChanged"); + string targetGate = TargetGate(request, preflight.Scan, target); + if (targetGate != null) throw new InvalidOperationException(targetGate); + var inspector = new MssqlImportScriptInspector(request.DatabaseName); + foreach (var next in input.ReadBatches(cancellation)) + { + cancellation.ThrowIfCancellationRequested(); batch = next; inspector.Observe(batch); + var previousPhase = phase; + phase = preflight.Scan.Script.Kind == MssqlImportScriptKind.Generic ? MssqlImportPhase.None : inspector.Phase; + Publish(MssqlImportStage.Executing, phase != previousPhase); + cancellation.ThrowIfCancellationRequested(); + var before = session.ReadState(cancellation); RequireState(before); + if (inspector.UsesNativeLob && !lobInitialized && !inspector.InitializesNativeLob) throw new InvalidOperationException("LobInitializationMissing"); + if (inspector.InitializesNativeLob) lobInitialized = true; + try + { + cancellation.ThrowIfCancellationRequested(); unacknowledgedExecution = true; + session.ExecuteBatch(batch, cancellation); + } + catch (MssqlImportBatchException error) + { + unacknowledgedExecution = false; + failures = checked(failures + 1); if (error.OutcomeUncertain) uncertain = batch.Number; + HandleSqlError(error, before, inspector.UsesNativeLob); + continue; + } + cancellation.ThrowIfCancellationRequested(); + var after = session.ReadState(cancellation); RequireState(after); + if (lobInitialized) RequireLob(false); + successfulBytes = checked(successfulBytes + batch.EndByte - boundary); boundary = batch.EndByte; + successes = checked(successes + 1); acknowledged = batch.Number; unacknowledgedExecution = false; + Publish(MssqlImportStage.Executing); + } + batch = null; phase = MssqlImportPhase.None; Publish(MssqlImportStage.Verifying, true); + cancellation.ThrowIfCancellationRequested(); + if (input.ExecutionSha256 == null || !string.Equals(input.ExecutionSha256, preflight.Scan.Sha256, StringComparison.Ordinal)) throw new InvalidOperationException("DigestMismatch"); + var finalState = session.ReadState(cancellation); RequireState(finalState); + if (finalState.TransactionCount != 0 || finalState.XactState != 0) throw new InvalidOperationException("EofTransactionOpen"); + if (!SameTarget(preflight.Target, session.ReadTarget(cancellation))) throw new InvalidOperationException("TargetChanged"); + if (lobInitialized) RequireLob(true); + summary = failures == 0 ? "AllBatchesExecuted;NoDataContentValidation" : "AllBatchesProcessedWithErrors;FullRestoreNotValidated"; + if (failures == 0 && preflight.Scan.Script.Kind == MssqlImportScriptKind.NativeSchema) + { + var counts = session.CountTargetRows((tables, rows) => { Publish(MssqlImportStage.Verifying); cancellation.ThrowIfCancellationRequested(); }, cancellation); + if (counts.Tables != preflight.Scan.Script.ExpectedTables || counts.Rows != preflight.Scan.Script.ExpectedRows) throw new InvalidOperationException("SummaryMismatch"); + summary = "NativeSummaryCountsMatched;NotColumnContentValidation"; + } + cancellation.ThrowIfCancellationRequested(); + successfulBytes = checked(successfulBytes + preflight.Scan.FileBytes - boundary); boundary = preflight.Scan.FileBytes; + status = failures == 0 ? MssqlImportStatus.Completed : MssqlImportStatus.CompletedWithErrors; + } + catch (OperationCanceledException) + { + status = cancellation.IsCancellationRequested ? MssqlImportStatus.Cancelled : MssqlImportStatus.Failed; + summary = cancellation.IsCancellationRequested ? "Cancelled;PreviouslyCommittedWritesMayRemain" : "ExecutionOutcomeUnknown"; + if (batch != null && unacknowledgedExecution) uncertain = batch.Number; + } + catch (Exception error) + { + status = MssqlImportStatus.Failed; + if (!summary.StartsWith("SqlBatchFailed", StringComparison.Ordinal) && !logIncomplete) summary = SafeCode(error, "ImportFailed"); + if (batch != null && unacknowledgedExecution) uncertain = batch.Number; + var sql = error as MssqlImportBatchException; + if (sql != null) + { + try { log.WriteError(new MssqlImportBatch(0, 0, 0, 0, 0, string.Empty), sql, "Stop;Origin=Probe;DuringBatch=" + (batch == null ? "0" : batch.Number.ToString(CultureInfo.InvariantCulture))); log.Flush(); } + catch { MarkLogIncomplete(); } + if (cancellation.IsCancellationRequested && !logIncomplete) + { status = MssqlImportStatus.Cancelled; summary = "Cancelled;PreviouslyCommittedWritesMayRemain"; } + } + } + finally + { + try + { + if (session != null) cleanup = session.Cleanup() ?? new MssqlImportCleanup(false, false, false, "CleanupReceiptMissing"); + else cleanup = new MssqlImportCleanup(true, true, true, null); + } + catch { cleanup = new MssqlImportCleanup(false, false, false, "CleanupFailed"); } + try { if (session != null) session.Dispose(); } + catch { cleanup = new MssqlImportCleanup(cleanup.CommandEnded, false, cleanup.TransactionCleanupConfirmed, "SessionReleaseFailed"); } + try { input.Dispose(); } catch { summary += ";InputReleaseFailed"; if (status != MssqlImportStatus.Failed) status = MssqlImportStatus.CleanupUncertain; } + if (cleanup == null || !cleanup.CommandEnded || !cleanup.SessionReleased || !cleanup.TransactionCleanupConfirmed) + { + summary += ";CleanupUnconfirmed"; + if (status != MssqlImportStatus.Failed) status = MssqlImportStatus.CleanupUncertain; + } + try { log.WriteEnd(Result()); } catch { MarkLogIncomplete(); } + try { log.Dispose(); } catch { MarkLogIncomplete(); } + Publish(MssqlImportStage.Finished, true); + } + } + return Result(); + } + + private void HandleSqlError(MssqlImportBatchException error, MssqlImportSessionState before, bool protocol) + { + bool skip = false; string stateSummary = string.Empty; MssqlImportBatchException probeFailure = null; + // Cancellation with SQL details must still log the original complete detail list. + if (!cancellation.IsCancellationRequested) + { + try + { + var after = session.ReadState(cancellation); RequireState(after); + if (lobInitialized) { RequireLob(true); } + skip = request.SkipSqlErrors && !protocol && !error.OutcomeUncertain && error.Errors.Count != 0 && + error.Errors.All(e => e.Class >= 11 && e.Class <= 16 && !UnsafeErrorNumber(e.Number)) && + before.TransactionCount == 0 && before.XactState == 0 && after.TransactionCount == 0 && after.XactState == 0; + stateSummary = ";TransactionCount=" + after.TransactionCount.ToString(CultureInfo.InvariantCulture) + ";XactState=" + after.XactState.ToString(CultureInfo.InvariantCulture) + ";DatabaseId=" + after.DatabaseId.ToString(CultureInfo.InvariantCulture); + } + catch (Exception stateError) + { + skip = false; stateSummary = ";StateCheck=" + SafeCode(stateError, "StateUnconfirmed"); + probeFailure = stateError as MssqlImportBatchException; + } + } + if (protocol) stateSummary += ";NativeLobBatch"; + if (!skip) summary = "SqlBatchFailed"; + try + { + log.WriteError(batch, error, (cancellation.IsCancellationRequested ? "Cancel" : skip ? "Skip" : "Stop") + ";Origin=Source" + stateSummary); + if (probeFailure != null) log.WriteError(new MssqlImportBatch(0, 0, 0, 0, 0, string.Empty), probeFailure, "Stop;Origin=Probe;DuringBatch=" + batch.Number.ToString(CultureInfo.InvariantCulture)); + log.Flush(); + } + catch { MarkLogIncomplete(); throw; } + cancellation.ThrowIfCancellationRequested(); + if (!skip) { summary = "SqlBatchFailed"; throw new InvalidOperationException("SqlBatchFailed"); } + skippedBytes = checked(skippedBytes + batch.EndByte - boundary); boundary = batch.EndByte; acknowledged = batch.Number; + Publish(MssqlImportStage.Executing); + } + private static bool UnsafeErrorNumber(int number) + { switch (number) { case -2: case 0: case 11: case 20: case 64: case 233: case 596: case 10053: case 10054: case 10060: return true; default: return false; } } + private void RequireState(MssqlImportSessionState state) + { if (state == null || !state.IsOpen || state.DatabaseId != preflight.Target.DatabaseId || state.TransactionCount < 0 || state.XactState < -1 || state.XactState > 1) throw new InvalidOperationException("SessionStateInvalid"); } + private void RequireLob(bool terminal) + { + if (!preflight.Scan.Script.NativeJobId.HasValue) throw new InvalidOperationException("LobStateInvalid"); + var state = session.ReadLobState(preflight.Scan.Script.NativeJobId.Value, cancellation); + if (state == null || !state.Exists || state.RowCount != 1 || state.Failed || state.Sequence < 0 || state.ConsumedThrough < 0 || + (state.Consumed ? state.Sequence != state.ConsumedThrough : state.Sequence <= 0 || state.ConsumedThrough != state.Sequence - 1) || terminal && !state.Consumed) + throw new InvalidOperationException("LobStateInvalid"); + } + private void MarkLogIncomplete() + { logIncomplete = true; if (!summary.Contains("LogIncomplete")) summary += ";LogIncomplete"; if (status != MssqlImportStatus.Failed) status = MssqlImportStatus.Failed; } + private MssqlImportResult Result() + { return new MssqlImportResult(request.JobId, status, preflight.Scan.FileBytes, successfulBytes, skippedBytes, successes, failures, acknowledged, uncertain, log.Path, cleanup, summary, log.Tail.TotalErrors, clock.Elapsed); } + private void Stopping() + { + lock (reportGate) + { + if (finished || latest == null || latest.Stage == MssqlImportStage.Stopping) return; + latest = Snapshot(MssqlImportStage.Stopping, latest, null); Notify(observer, latest); + } + } + private MssqlImportProgress Snapshot(MssqlImportStage stage, MssqlImportProgress previous, MssqlImportEstimate estimate) + { + // Cancellation thread only copies an already immutable worker snapshot. + if (previous != null) return new MssqlImportProgress(request.JobId, previous.FileBytes, stage, previous.ScannedBytes, previous.SuccessfulBytes, previous.SkippedBytes, + previous.SuccessfulBatches, previous.FailedBatches, previous.BatchNumber, previous.StartLine, previous.EndLine, previous.StartByte, previous.EndByte, + previous.Phase, elapsed: clock.Elapsed, recentErrorText: previous.RecentErrorText, logPath: previous.LogPath, totalErrors: previous.TotalErrors, logTruncated: previous.LogTruncated); + return new MssqlImportProgress(request.JobId, preflight.Scan.FileBytes, stage, successfulBytes: successfulBytes, skippedBytes: skippedBytes, + successfulBatches: successes, failedBatches: failures, batchNumber: batch == null ? 0 : batch.Number, startLine: batch == null ? 0 : batch.StartLine, + endLine: batch == null ? 0 : batch.EndLine, startByte: batch == null ? 0 : batch.StartByte, endByte: batch == null ? 0 : batch.EndByte, phase: phase, + elapsed: clock.Elapsed, remaining: estimate == null ? null : estimate.Remaining, estimatedFinish: estimate == null ? null : estimate.EstimatedFinish, + recentErrorText: log.Tail.Snapshot() + (logIncomplete ? "\r\nLogIncomplete" : ""), logPath: log.Path, totalErrors: log.Tail.TotalErrors, logTruncated: log.Tail.Truncated); + } + private void Publish(MssqlImportStage stage, bool force = false) + { + lock (reportGate) + { + if (finished) return; + if (cancellation.IsCancellationRequested && stage != MssqlImportStage.Finished) stage = MssqlImportStage.Stopping; + var now = DateTime.UtcNow; var p = Snapshot(stage, null, null); estimator.Observe(p, now); + latest = Snapshot(stage, null, estimator.Estimate(now)); + bool shouldReport = estimator.ShouldReport(latest, now); + if (stage == MssqlImportStage.Finished) finished = true; + if (force || shouldReport) Notify(observer, latest); + } + } + } + } +} \ No newline at end of file diff --git a/mySQLPunk/mySQLPunk.csproj b/mySQLPunk/mySQLPunk.csproj index e721bd4..b1511c8 100644 --- a/mySQLPunk/mySQLPunk.csproj +++ b/mySQLPunk/mySQLPunk.csproj @@ -367,6 +367,7 @@ + diff --git a/tests/SmokeTests.MssqlImport.Worker.cs b/tests/SmokeTests.MssqlImport.Worker.cs index 55236fe..658b5ce 100644 --- a/tests/SmokeTests.MssqlImport.Worker.cs +++ b/tests/SmokeTests.MssqlImport.Worker.cs @@ -232,3 +232,327 @@ private static void MssqlImportProgressWindowAndThrottle() } } + +// These tests drive the actual importer service with real bounded input/log and no database. +public static partial class SmokeTests +{ + private sealed class ImportWorkerSession : IMssqlImportSession + { + internal int Executes, States, Targets, Lobs, Counts, Cleanups, Disposes, Effects; + internal Action Execute; + internal Func State; + internal Func Target; + internal Func Lob; + internal Func Finish; + internal Action Counting; + internal MssqlImportCounts CountValue = new MssqlImportCounts(1, 0); + public MssqlImportTarget ReadTarget(System.Threading.CancellationToken token) + { token.ThrowIfCancellationRequested(); Targets++; return Target == null ? WorkerTarget() : Target(); } + public MssqlImportSessionState ReadState(System.Threading.CancellationToken token) + { token.ThrowIfCancellationRequested(); States++; return State == null ? WorkerState() : State(); } + public MssqlImportLobState ReadLobState(Guid job, System.Threading.CancellationToken token) + { token.ThrowIfCancellationRequested(); Lobs++; return Lob == null ? new MssqlImportLobState(true, 1, 1, 1, true, false) : Lob(job); } + public void ExecuteBatch(MssqlImportBatch batch, System.Threading.CancellationToken token) + { token.ThrowIfCancellationRequested(); Executes++; if (Execute != null) Execute(batch, token); } + public MssqlImportCounts CountTargetRows(Action progress, System.Threading.CancellationToken token) + { Counts++; if (Counting != null) Counting(token); token.ThrowIfCancellationRequested(); progress(CountValue.Tables, CountValue.Rows); return CountValue; } + public void CancelActiveCommand() { } + public MssqlImportCleanup Cleanup() + { Cleanups++; return Finish == null ? new MssqlImportCleanup(true, true, true, null) : Finish(); } + public void Dispose() { Disposes++; } + } + private sealed class ImportWorkerFixture : IDisposable + { + internal readonly string DirectoryPath, Source; + internal readonly ImportWorkerSession Session = new ImportWorkerSession(); + internal readonly System.Collections.Generic.List Progress = new System.Collections.Generic.List(); + internal MssqlImportService Service; + internal MssqlImportRequest Request; + internal int Opens; + internal Func LogFactory; + internal ImportWorkerFixture(string sql = "SELECT 1;\r\nGO\r\nSELECT 2;\r\nGO\r\n", bool skip = false) + { + DirectoryPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "mySQLPunk", "ImportTestFixtures", Guid.NewGuid().ToString("N")); + Directory.CreateDirectory(DirectoryPath); Source = Path.Combine(DirectoryPath, "worker.sql"); + File.WriteAllText(Source, sql, new UTF8Encoding(false, true)); + Request = new MssqlImportRequest(Guid.NewGuid(), Source, "fixture", skip); + Service = new MssqlImportService(() => { Opens++; return Opens == 1 ? new ImportWorkerSession() : Session; }, + job => LogFactory == null ? new MssqlImportLog(job, DirectoryPath) : LogFactory(job)); + } + internal MssqlImportResult Run(System.Threading.CancellationToken token = default(System.Threading.CancellationToken)) + { using (var preflight = Service.Preflight(Request, Progress.Add, token)) { Assert(preflight.Passed, "Valid fixture preflight passes."); return Service.Run(Request, preflight, Progress.Add, token); } } + public void Dispose() + { foreach (string file in Directory.GetFiles(DirectoryPath)) File.Delete(file); Directory.Delete(DirectoryPath); } + } + private static MssqlImportTarget WorkerTarget(int id = 7, bool writable = true, bool visible = true, long? objects = 0, bool? create = true, DateTime? date = null) + { return new MssqlImportTarget("fixture-server", "fixture", id, date ?? new DateTime(2026, 10, 13), "15.0", writable, visible, objects, create); } + private static MssqlImportSessionState WorkerState(int transaction = 0, int xact = 0, int id = 7, bool open = true) + { return new MssqlImportSessionState(open, id, transaction, xact); } + private static MssqlImportBatchException WorkerSqlError(int number = 547, int severity = 16, bool uncertain = false) + { return new MssqlImportBatchException(new[] { new MssqlImportSqlError(number, 1, severity, 1, "完整 detail 一"), new MssqlImportSqlError(50000, 2, 16, 2, "detail two") }, uncertain); } + private static readonly Guid WorkerNativeJob = new Guid("10000000-0000-0000-0000-000000000009"); + private static string WorkerNative(string body, bool schema = false, long tables = 0, long rows = 0) + { return "-- Source read mode: READ COMMITTED\r\n" + (schema ? "-- Restore into an empty, compatible target selected by the caller; existing objects fail.\r\n" : "") + body + "-- mysqlpunk-export-complete job=" + WorkerNativeJob.ToString("N") + " tables=" + tables + " rows=" + rows + "\r\n"; } + private static string WorkerLobInit() + { return "CREATE TABLE #mp_" + WorkerNativeJob.ToString("N") + "_s ([Sequence] bigint);\r\nGO\r\n"; } + + private static void MssqlImportWorkerStopAndSkip() + { + using (var f = new ImportWorkerFixture()) { + f.Session.Execute = (b, t) => { f.Session.Effects++; throw WorkerSqlError(); }; + var r = f.Run(); + Assert(r.Status == MssqlImportStatus.Failed && f.Session.Executes == 1 && f.Opens == 2, "DefaultStopsAtFirstError: no next batch, reconnect or replay."); + Assert(r.SuccessfulBatches == 0 && r.FailedBatches == 1 && r.ProcessedBytes == 0 && f.Session.Effects == 1, "PartialBatchEffectsAreNotReportedAsRows or successful coverage."); + string log = File.ReadAllText(r.LogPath); + Assert(log.Contains("完整 detail 一") && log.Contains("detail two"), "All provider SQL details survive default stop."); + } + using (var f = new ImportWorkerFixture(skip: true)) { + f.Session.Execute = (b, t) => { if (b.Number == 1) throw WorkerSqlError(); }; + var r = f.Run(); + Assert(r.Status == MssqlImportStatus.CompletedWithErrors && f.Session.Executes == 2 && r.SuccessfulBatches == 1 && r.FailedBatches == 1, + "SkipContinuesOnlySafeBatch executes actual next SQL."); + Assert(r.SkippedBytes > 0 && r.ProcessedBytes == new FileInfo(f.Source).Length && r.LastAcknowledgedBatch == 2 && f.Session.Counts == 0, "Skipped EOF coverage and summary remain distinct."); + } + foreach (int code in new[] { -2, 0, 11, 20, 64, 233, 10053, 10054, 10060 }) using (var f = new ImportWorkerFixture(skip: true)) { + f.Session.Execute = (b, t) => { throw WorkerSqlError(code); }; + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 1, "Never skip transport/timeout/attention code " + code); + } + foreach (int severity in new[] { 10, 17, 20 }) using (var f = new ImportWorkerFixture(skip: true)) { + f.Session.Execute = (b, t) => { throw WorkerSqlError(severity: severity); }; + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 1, "Every detail must be ordinary severity."); + } + using (var f = new ImportWorkerFixture(skip: true)) { + f.Session.Execute = (b, t) => { throw WorkerSqlError(uncertain: true); }; + var r = f.Run(); Assert(r.UncertainBatch == 1 && f.Session.Executes == 1, "Unknown outcome is separate and never replayed."); + } + foreach (var unsafeState in new[] { WorkerState(1), WorkerState(0, -1), WorkerState(id: 8), WorkerState(open: false) }) using (var f = new ImportWorkerFixture(skip: true)) { + f.Session.State = () => f.Session.Executes == 0 ? WorkerState() : unsafeState; + f.Session.Execute = (b, t) => { throw WorkerSqlError(); }; + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 1, "Unsafe post-state blocks skip."); + } + } + private sealed class WorkerFlushStream : MemoryStream + { + internal bool Fail, CancelOnFlush; + internal System.Threading.CancellationTokenSource Cancellation; + public override void Flush() + { if (CancelOnFlush) { CancelOnFlush = false; Cancellation.Cancel(); } if (Fail) throw new IOException("fixture flush fault"); base.Flush(); } + } + private static void MssqlImportWorkerFlushAndLogFaults() + { + using (var f = new ImportWorkerFixture(skip: true)) { + var stream = new WorkerFlushStream(); + f.LogFactory = job => new MssqlImportLog(job, f.DirectoryPath, p => stream); + f.Session.Execute = (b, t) => { stream.Fail = true; throw WorkerSqlError(); }; + var r = f.Run(); + Assert(f.Session.Executes == 1 && r.Status == MssqlImportStatus.Failed && r.SkippedBytes == 0 && r.ValidationSummary.Contains("LogIncomplete"), "FlushFailsBeforeSkip actual log stream prevents NextBatchCalls."); + } + using (var f = new ImportWorkerFixture()) { + var stream = new WorkerFlushStream(); f.LogFactory = job => new MssqlImportLog(job, f.DirectoryPath, p => stream); + f.Session.Counting = t => { stream.Fail = true; }; + f.Session.Execute = (b, t) => { if (b.Number == 2) stream.Fail = true; }; + var r = f.Run(); Assert(r.Status == MssqlImportStatus.Failed && r.ValidationSummary.Contains("LogIncomplete"), "Terminal logging failure cannot claim successful saved log."); + } + } + private static void MssqlImportWorkerPreflightOwnership() + { + using (var f = new ImportWorkerFixture("SELECT '\u0000';")) { + using (var p = f.Service.Preflight(f.Request, null, default(System.Threading.CancellationToken))) { + Assert(!p.Passed && f.Opens == 0 && p.Issues[0].Code == "EmbeddedNul" && p.Issues[0].Line > 0, "Parser preflight failure precedes any session and exposes safe coordinates."); + } + } + using (var f = new ImportWorkerFixture()) { + using (var p = f.Service.Preflight(f.Request, null, default(System.Threading.CancellationToken))) { + Assert(p.Passed && File.Exists(p.LogPath), "Preflight retains real established log."); + var wrong = new MssqlImportRequest(f.Request.JobId, f.Source, "fixture", true); + Assert(f.Service.Run(wrong, p, null, default(System.Threading.CancellationToken)).Status == MssqlImportStatus.Failed && f.Session.Executes == 0, "Changed skip policy invalidates preflight."); + var r = f.Service.Run(f.Request, p, null, default(System.Threading.CancellationToken)); + Assert(r.Status == MssqlImportStatus.Completed, "Matching request claims once."); + int calls = f.Session.Executes; + Assert(f.Service.Run(f.Request, p, null, default(System.Threading.CancellationToken)).Status == MssqlImportStatus.Failed && f.Session.Executes == calls && f.Opens == 2, "ReusedPreflightIsRejected before new session."); + } + } + using (var f = new ImportWorkerFixture()) { + f.Session.Target = () => WorkerTarget(date: new DateTime(2026, 10, 14)); + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 0, "Recreated target fails identity before first write."); + } + using (var f = new ImportWorkerFixture()) { + var p = f.Service.Preflight(f.Request, null, default(System.Threading.CancellationToken)); p.Dispose(); p.Dispose(); + Assert(f.Service.Run(f.Request, p, null, default(System.Threading.CancellationToken)).Status == MssqlImportStatus.Failed && f.Opens == 1, "Disposed preflight cannot execute."); + } + using (var f = new ImportWorkerFixture()) { + var missing = new MssqlImportRequest(Guid.NewGuid(), f.Source, " "); + using (var p = f.Service.Preflight(missing, null, default(System.Threading.CancellationToken))) Assert(!p.Passed && f.Opens == 0, "Missing target rejects pre-IO/session."); + } + } + private static void MssqlImportWorkerEofAndNative() + { + using (var f = new ImportWorkerFixture(skip: true)) { + f.Session.Execute = (b, t) => { if (b.Number == 1) throw WorkerSqlError(); }; + f.Session.State = () => f.Session.States >= 5 ? WorkerState(1, 1) : WorkerState(); + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 2, "SkippedRunStillChecksEofState."); + } + using (var f = new ImportWorkerFixture()) { + f.Session.State = () => WorkerState(f.Session.Executes == 1 ? 1 : 0, f.Session.Executes == 1 ? 1 : 0); + Assert(f.Run().Status == MssqlImportStatus.Completed, "Successful generic transaction may span GO then commit."); + } + string lobSql = WorkerNative(WorkerLobInit() + "SELECT 2;\r\nGO\r\n"); + foreach (var state in new[] { new MssqlImportLobState(true, 1, 2, 1, false, false), new MssqlImportLobState(false, 0, 0, 0, false, false), new MssqlImportLobState(true, 2, 1, 1, true, false), new MssqlImportLobState(true, 1, 1, 1, true, true) }) using (var f = new ImportWorkerFixture(lobSql)) { + f.Session.Lob = job => { Assert(job == WorkerNativeJob, "LOB query receives validated exact job."); return state; }; + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Counts == 0, "NativeData missing/duplicate/failed/pending EOF cannot complete."); + } + using (var f = new ImportWorkerFixture(lobSql, true)) { + f.Session.Execute = (b, t) => { throw WorkerSqlError(); }; + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 1, "Native init error fatal even transaction0."); + } + using (var f = new ImportWorkerFixture(WorkerNative(WorkerLobInit() + "UPDATE #mp_" + WorkerNativeJob.ToString("N") + "_s SET [Sequence]=1;\r\nGO\r\nSELECT 1;\r\nGO\r\n"), true)) { + f.Session.Execute = (b, t) => { if (b.Number == 2) throw WorkerSqlError(); }; + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 2, "Native assembly/commit error cannot skip."); + } + string nativeSchema = WorkerNative("CREATE TABLE dbo.t(i int);\r\nGO\r\n", true, 1, 0); + using (var f = new ImportWorkerFixture(nativeSchema)) { + var r = f.Run(); Assert(r.Status == MssqlImportStatus.Completed && f.Session.Counts == 1 && r.ProcessedBytes == new FileInfo(f.Source).Length, "NativeSchema summary count and trailing footer coverage."); + } + using (var f = new ImportWorkerFixture(nativeSchema)) { + f.Session.CountValue = new MssqlImportCounts(1, 9); + Assert(f.Run().Status == MssqlImportStatus.Failed, "Footer row mismatch blocks success."); + } + foreach (var target in new[] { WorkerTarget(visible: false, objects: null), WorkerTarget(objects: 1), WorkerTarget(create: false) }) using (var f = new ImportWorkerFixture(nativeSchema)) { + f.Session.Target = () => target; + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 0, "Execution target native capabilities rechecked."); + } + } + private static void MssqlImportWorkerCancellationAndCleanup() + { + using (var f = new ImportWorkerFixture(skip: true)) using (var stop = new System.Threading.CancellationTokenSource()) { + f.Session.Execute = (b, t) => { stop.Cancel(); throw WorkerSqlError(uncertain: true); }; + var r = f.Run(stop.Token); + Assert(r.Status == MssqlImportStatus.Cancelled && f.Session.Executes == 1 && r.UncertainBatch == 1 && r.FailedBatches == 1, "Cancellation retains SQL error details and blocks skip."); + Assert(File.ReadAllText(r.LogPath).Contains("detail two") && f.Progress.Exists(p => p.Stage == MssqlImportStage.Stopping), "Stopping and SQL details survive cancellation."); + } + using (var f = new ImportWorkerFixture()) using (var stop = new System.Threading.CancellationTokenSource()) { + f.Session.Execute = (b, t) => { stop.Cancel(); t.ThrowIfCancellationRequested(); }; + f.Session.Finish = () => new MssqlImportCleanup(false, true, false, "CommandStillActive"); + Assert(f.Run(stop.Token).Status == MssqlImportStatus.CleanupUncertain && f.Session.Executes == 1, "Unacknowledged command cannot be called cancelled."); + } + using (var f = new ImportWorkerFixture(skip: true)) using (var stop = new System.Threading.CancellationTokenSource()) { + var stream = new WorkerFlushStream { Cancellation = stop }; + f.LogFactory = job => new MssqlImportLog(job, f.DirectoryPath, p => stream); + f.Session.Execute = (b, t) => { stream.CancelOnFlush = true; throw WorkerSqlError(); }; + Assert(f.Run(stop.Token).Status == MssqlImportStatus.Cancelled && f.Session.Executes == 1, "Cancel during error flush cannot schedule next."); + } + using (var f = new ImportWorkerFixture()) { + f.Session.Execute = (b, t) => { throw WorkerSqlError(); }; + f.Session.Finish = () => { throw new IOException("cleanup fault"); }; + var r = f.Run(); Assert(r.Status == MssqlImportStatus.Failed && r.ValidationSummary.Contains("SqlBatchFailed") && r.ValidationSummary.Contains("Cleanup"), "Original failed result survives cleanup exception."); + } + using (var f = new ImportWorkerFixture(WorkerNative("CREATE TABLE dbo.t(i int);\r\nGO\r\n", true, 1))) using (var stop = new System.Threading.CancellationTokenSource()) { + f.Session.Counting = t => { stop.Cancel(); t.ThrowIfCancellationRequested(); }; + Assert(f.Run(stop.Token).Status == MssqlImportStatus.Cancelled && f.Session.Counts == 1, "Verification COUNT_BIG cancellation is acknowledged after cleanup."); + } + } + private static void MssqlImportWorkerPhaseAndBoundaries() + { + string sql = WorkerNative("CREATE TABLE dbo.t(i int);\r\nGO\r\nCREATE NONCLUSTERED INDEX IX ON dbo.t(i);\r\nGO\r\nALTER TABLE dbo.t WITH CHECK ADD CONSTRAINT ck CHECK(i>0);\r\nGO\r\n", true, 1); + using (var f = new ImportWorkerFixture(sql)) { + f.Session.Execute = (b, t) => { + var p = f.Progress[f.Progress.Count - 1]; + if (b.Number == 2) Assert(p.Phase == MssqlImportPhase.Indexes && !p.Remaining.HasValue, "Index phase immediately disables ETA before command."); + if (b.Number == 3) Assert(p.Phase == MssqlImportPhase.Constraints && !p.Remaining.HasValue, "Constraint phase immediately disables ETA before command."); + Assert(p.SuccessfulBatches == b.Number - 1, "Read-ahead is not acknowledged progress."); + }; + Assert(f.Run().Status == MssqlImportStatus.Completed, "Bounded phase lexer preserves SQL execution."); + } + using (var f = new ImportWorkerFixture("SELECT '#mp_10000000000000000000000000000009_s CREATE INDEX FOREIGN KEY';\r\nGO\r\n")) { + using (var p = f.Service.Preflight(f.Request, null, default(System.Threading.CancellationToken))) { + Assert(p.Scan.Script.Kind == MssqlImportScriptKind.Generic, "String decoys are generic."); + Assert(f.Service.Run(f.Request, p, value => { throw new InvalidOperationException("observer"); }, default(System.Threading.CancellationToken)).Status == MssqlImportStatus.Completed, "Observer failure cannot alter execution truth."); + } + } + } +} +public static partial class SmokeTests +{ + private static void MssqlImportWorkerAdditionalBoundaries() + { + using (var f = new ImportWorkerFixture()) { + f.Session.Execute = (b, t) => { throw new IOException("unknown transport"); }; + var r = f.Run(); Assert(r.Status == MssqlImportStatus.Failed && r.UncertainBatch == 1 && r.ProcessedBytes == 0, "Non-SQL execution failure is uncertain and unacknowledged."); + } + using (var f = new ImportWorkerFixture()) { + f.Session.State = () => { if (f.Session.Executes != 0) throw WorkerSqlError(uncertain: true); return WorkerState(); }; + var r = f.Run(); Assert(r.Status == MssqlImportStatus.Failed && File.ReadAllText(r.LogPath).Contains("detail two"), "Probe SQL detail also survives worker failure."); + } + using (var f = new ImportWorkerFixture()) using (var stop = new System.Threading.CancellationTokenSource()) { + f.Session.State = () => { if (f.Session.Executes == 1) { stop.Cancel(); stop.Token.ThrowIfCancellationRequested(); } return WorkerState(); }; + var r = f.Run(stop.Token); Assert(r.Status == MssqlImportStatus.Cancelled && f.Session.Executes == 1 && r.SuccessfulBatches == 0, "Cancellation during post-state prevents acknowledgement and next SQL."); + } + using (var f = new ImportWorkerFixture()) using (var stop = new System.Threading.CancellationTokenSource()) { + using (var p = f.Service.Preflight(f.Request, null, stop.Token)) { + var r = f.Service.Run(f.Request, p, value => { if (value.Stage == MssqlImportStage.Finished) stop.Cancel(); f.Progress.Add(value); }, stop.Token); + Assert(r.Status == MssqlImportStatus.Completed && f.Progress[f.Progress.Count - 1].Stage == MssqlImportStage.Finished, "Late cancellation cannot publish stopping after terminal callback."); + } + } + using (var f = new ImportWorkerFixture()) { + f.LogFactory = job => { throw new IOException("log create fault"); }; + using (var p = f.Service.Preflight(f.Request, null, default(System.Threading.CancellationToken))) Assert(!p.Passed && f.Session.Executes == 0 && f.Opens == 1, "Log creation failure blocks execution factory."); + } + using (var f = new ImportWorkerFixture()) { + using (var p = f.Service.Preflight(f.Request, null, default(System.Threading.CancellationToken))) { + var original = p.Scan; + // Same real retained input; alter only expected digest through internal immutable construction. + var input = MssqlImportInput.Open(f.Source, "fixture"); + var log = new MssqlImportLog(f.Request.JobId, f.DirectoryPath); log.WriteStart(f.Request, original, p.Target); + var badScan = new MssqlImportScan(original.FileBytes, original.BatchCount, original.MaxBatchCodeUnits, original.EncodingName, "mismatched", original.Script); + using (var changed = new MssqlImportPreflight(f.Service, f.Request, Path.GetFullPath(f.Source), input, badScan, p.Target, log, new MssqlImportIssue[0])) { + var r = f.Service.Run(f.Request, changed, null, default(System.Threading.CancellationToken)); + Assert(r.Status == MssqlImportStatus.Failed && r.ValidationSummary.Contains("DigestMismatch"), "Every EOF compares actual execution digest to retained scan."); + } + } + } + using (var f = new ImportWorkerFixture()) { + using (var p = f.Service.Preflight(f.Request, null, default(System.Threading.CancellationToken))) { + var entered = new System.Threading.ManualResetEventSlim(); var release = new System.Threading.ManualResetEventSlim(); + f.Session.Execute = (b, t) => { if (b.Number == 1) { entered.Set(); Assert(release.Wait(3000), "Fixture release arrives."); } }; + var task = System.Threading.Tasks.Task.Run(() => f.Service.Run(f.Request, p, null, default(System.Threading.CancellationToken))); + try { + Assert(entered.Wait(3000), "Running worker owns first command."); p.Dispose(); + Assert(f.Service.Run(f.Request, p, null, default(System.Threading.CancellationToken)).Status == MssqlImportStatus.Failed && f.Opens == 2, "Concurrent/stale preflight cannot acquire or dispose running worker."); + } finally { release.Set(); } + Assert(task.GetAwaiter().GetResult().Status == MssqlImportStatus.Completed && f.Session.Executes == 2, "Stale dispose leaves retained execution input/log alive."); + entered.Dispose(); release.Dispose(); + } + } + using (var f = new ImportWorkerFixture()) using (var stop = new System.Threading.CancellationTokenSource()) { + var entered = new System.Threading.ManualResetEventSlim(); var release = new System.Threading.ManualResetEventSlim(); var stopping = new System.Threading.ManualResetEventSlim(); + f.Session.Execute = (b, t) => { entered.Set(); Assert(release.Wait(3000), "Blocked provider fixture releases."); t.ThrowIfCancellationRequested(); }; + using (var p = f.Service.Preflight(f.Request, null, stop.Token)) { + var task = System.Threading.Tasks.Task.Run(() => f.Service.Run(f.Request, p, value => { if (value.Stage == MssqlImportStage.Stopping) stopping.Set(); }, stop.Token)); + try { Assert(entered.Wait(3000), "Provider fixture enters."); stop.Cancel(); Assert(stopping.Wait(1000) && !task.IsCompleted && f.Session.Cleanups == 0, "Stopping precedes command unwind and no premature terminal/cleanup."); } + finally { release.Set(); } + Assert(task.GetAwaiter().GetResult().Status == MssqlImportStatus.Cancelled && f.Session.Executes == 1 && f.Session.Cleanups == 1, "Actual command unwind precedes truthful cleanup/cancelled result."); + } + entered.Dispose(); release.Dispose(); stopping.Dispose(); + } + using (var f = new ImportWorkerFixture()) using (var stop = new System.Threading.CancellationTokenSource()) { + f.Session.State = () => { if (f.Session.Executes == 1) { stop.Cancel(); throw WorkerSqlError(uncertain: true); } return WorkerState(); }; + var r = f.Run(stop.Token); Assert(r.Status == MssqlImportStatus.Cancelled && File.ReadAllText(r.LogPath).Contains("detail two"), "Cancellation with SQL probe details must log then cancel."); + } + using (var f = new ImportWorkerFixture(skip: true)) { + f.Session.Execute = (b, t) => { throw WorkerSqlError(); }; + f.Session.State = () => { if (f.Session.Executes != 0) throw new MssqlImportBatchException(new[] { new MssqlImportSqlError(50000, 1, 16, 1, "distinct safety probe detail") }); return WorkerState(); }; + var r = f.Run(); string log = File.ReadAllText(r.LogPath); + Assert(r.Status == MssqlImportStatus.Failed && f.Session.Executes == 1 && log.Contains("detail two") && log.Contains("RelativeLine=1 SourceLine=unknown Message=distinct safety probe detail") && log.Contains("Origin=Probe;DuringBatch=1"), "Safety probe failure cannot discard either SQL error collection."); + } + using (var f = new ImportWorkerFixture(skip: true)) { + f.Session.State = () => f.Session.Executes == 0 ? WorkerState(1, 1) : WorkerState(); + f.Session.Execute = (b, t) => { throw WorkerSqlError(); }; + Assert(f.Run().Status == MssqlImportStatus.Failed && f.Session.Executes == 1, "Pre-batch open transaction prohibits skipping even after rollback0."); + } + foreach (int failAt in new[] { 1, 2, 3 }) using (var f = new ImportWorkerFixture(WorkerNative(WorkerLobInit() + "SELECT 2;\r\nGO\r\n"), true)) { + f.Session.Lob = job => f.Session.Lobs >= failAt ? new MssqlImportLobState(true, 1, 2, 1, false, false) : new MssqlImportLobState(true, 1, 1, 1, true, false); + f.Session.Execute = (b, t) => { if (b.Number == 2 && failAt < 3) throw WorkerSqlError(); }; + Assert(f.Run().Status == MssqlImportStatus.Failed, "Ordinary error/EOF cannot bypass initialized LOB terminal gate."); + } + } +} \ No newline at end of file diff --git a/tests/SmokeTests.cs b/tests/SmokeTests.cs index ac0dd7b..e09352c 100644 --- a/tests/SmokeTests.cs +++ b/tests/SmokeTests.cs @@ -31,6 +31,13 @@ public static int Main(string[] args) if (args.Length != 0) return SnapshotCrashChild(args); if (Environment.GetEnvironmentVariable("MYSQLPUNK_MSSQL_WIZARD_PREVIEW") == "1") return WizardPreview(); int passed = 0; + Run("MSSQL import worker service boundaries", MssqlImportWorkerAdditionalBoundaries, ref passed); + Run("MSSQL import worker service stop and skip", MssqlImportWorkerStopAndSkip, ref passed); + Run("MSSQL import worker service log faults", MssqlImportWorkerFlushAndLogFaults, ref passed); + Run("MSSQL import worker service ownership", MssqlImportWorkerPreflightOwnership, ref passed); + Run("MSSQL import worker service EOF", MssqlImportWorkerEofAndNative, ref passed); + Run("MSSQL import worker service cancellation", MssqlImportWorkerCancellationAndCleanup, ref passed); + Run("MSSQL import worker service phases", MssqlImportWorkerPhaseAndBoundaries, ref passed); Run("MSSQL import worker session options", MssqlImportConnectionOptions, ref passed); Run("MSSQL import worker session drain", MssqlImportSessionDrainsResults, ref passed); Run("MSSQL import worker session cancellation", MssqlImportSessionCancellationOwnership, ref passed); From 5c6541394482a9ee0c809eae398e3bd554e870f8 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 22:43:52 +0800 Subject: [PATCH 13/26] docs: record sequential import acceptance and wizard handoff --- docs/design/mssql-import/implementation-plan.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/design/mssql-import/implementation-plan.md b/docs/design/mssql-import/implementation-plan.md index aebc04b..56ecc07 100644 --- a/docs/design/mssql-import/implementation-plan.md +++ b/docs/design/mssql-import/implementation-plan.md @@ -10,7 +10,7 @@ **Spec:** [design.md](design.md),使用者於 2026-10-13 回覆「好,進實作」核准書面規格。 -**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 已實作與覆核通過(0982548/3ebf6b3,修正兩項 P2);Task2 log/ETA 已實作與覆核通過(0cc1657);Task3 專用連線層已實作與覆核通過(9df6437);Task4 開始。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 +**Status:** 使用者已明確授權進實作,沿用分工逐項覆核;隔離分支 codex/mssql-import 的 Task1 已實作與覆核通過(0982548/3ebf6b3,修正兩項 P2);Task2 log/ETA 已實作與覆核通過(0cc1657);Task3 專用連線層已實作與覆核通過(9df6437);Task4 循序 worker 已實作與覆核通過(0707bc9);Task5 開始。進度與技術裁決存於本 worktree 的 `.superpowers/sdd/implementation-plan/progress.md`;實際 DB 驗收仍待 Task6/7。 **Execution:** 保留先前選定的「分工實作並逐項覆核」。一次一位 implementer,各 task 經獨立覆核後才接下一項;最後整體覆核。build、native UI 與 DB tests 由單一 owner 串行執行,避免共享輸出/fixture 衝突。 @@ -22,7 +22,7 @@ - 嚴格 UTF-8 有/無 BOM、UTF-16 LE/BE 有 BOM;解碼後 U+0000 回報 EmbeddedNul,明示 v1 literal-NUL 相容邊界,不能誤稱 UTF-8 NUL 一定是無效編碼;保留原文及同一 session。支援獨立 GO/GO -- 註解,拒絕 GO n、同分隔行 block comment、SQLCMD 指令與跨 DB 的直接 USE。 - 預設不略過錯誤;略過對象為失敗 GO batch,不是單筆 row。timeout/斷線/log IO/未知交易/native LOB 失敗仍停止,不重連、重試、重播或續傳。 - 專用連線明確指定 Initial Catalog;ConnectRetryCount=0,單一 command,CommandTimeout=0。狀態查詢 5 秒、cleanup 10 秒,取消 10 秒無回應後只嘗試關閉本次 owned connection。 -- 不新增全檔外層 transaction、不自動清庫/DROP 使用者物件、不改 SNAPSHOT/recovery model/constraint trust、不 GRANT/KILL。 +- 不新增全檔外層 transaction、不自動清庫/DROP 使用者物件、不改 SNAPSHOT/recovery model/constraint trust、不 GRANT/KILL。 隔離驗收例外僅限新建 GUID-owned LocalDB 測試庫:WITHOUT LOGIN fixture users/custom roles 可作 GRANT/DENY 與 readonly/recreate target 測試;不擴張至 server login、master/msdb、Transfer 或既有真人帳號,清除仍須雙重 ownership/路徑驗證。 - 所有走到 EOF 的作業都做 session/交易/digest/已初始化 LOB 終態檢查,包括已略過錯誤者。native LOB 結尾要求唯一 state row、Failed=0、Consumed=1、Sequence=ConsumedThrough。 - error log 預設 `%LOCALAPPDATA%\mySQLPunk\ImportLogs\import--.log`;略過前落檔並 flush。UI 最近 100 筆或 64 KiB UTF-16 文字,先到者為準,完整路徑可見。 - 進度與 batch/line/byte/error 統計為 Int64;command/result drain/狀態處理完成才更新確認邊界。affected rows 不能標為實際匯入筆數。 @@ -122,11 +122,11 @@ **Interfaces:** 完成 Service.Preflight/Run;Preflight 保留 input/scan/target identity/已建立 log;Run 在新專用 execution session 重查相同 server/DB id/create_date 與能力,所有 batches 同線。 -- [ ] **Step 1: 先寫失敗的 fake-session tests。** `DefaultStopsAtFirstError`、`SkipContinuesOnlySafeBatch`:未勾後續0calls;勾選一般class11–16、前後交易0/XactState0、same DB、無LOB pending、log flush成功才下一批。任何 SqlError 嚴重/timeout/傳輸/不明 outcome 不可 skip,不比對 message 語言。`FlushFailsBeforeSkip` 注入真實log flush fault,斷言 `NextBatchCalls==0`。 -- [ ] **Step 2: 實作預檢→確認→執行流程。** 所有 input encoding/batch/native/目標/log 可寫性問題於第一個 DB write 前阻擋,parser失敗時execution factory calls=0;不同檔案/target/skip設定令預檢失效,ReusedPreflightIsRejected 測試第二次 Run 不送 SQL。一次一批,結果與 state 查明後才確認 bytes;目前batch可能部分生效,分開成功、失敗與未知批次。 -- [ ] **Step 3: 實作 native batch role/state gate 及 EOF。** native LOB initialization/assemble/commit 任一 error fatal,即使 XACT_STATE0;普通batch遇錯也查已初始化 native state。每個走到 EOF 的作業都查交易、identity、digest、LOB唯一state/Failed0/Consumed1/Sequence=ConsumedThrough,包含 skip/DataOnly;pending/missing/wrongjob 不得 amber完成。無錯 NativeSchema 才逐表 COUNT_BIG 對 footer tables/rows,核對可取消。 -- [ ] **Step 4: 實作取消/cleanup terminal tests。** 先 Stopping、不排下一批;Cancel10秒無回應只關本 session;cleanup10秒限時。自然 EOF 未結交易、取消在成功回應邊界、狀態查詢/COUNT_BIG/log flush 中取消、cleanup未確認都測。已失敗的原始結果不能被 cleanup exception 覆蓋;若最後 log失敗要顯示存檔未完整。 -- [ ] **Step 5: 跑 worker filter、提交。** `PartialBatchEffectsAreNotReportedAsRows`、`SkippedRunStillChecksEofState`、`NativeLobPendingAtEofFails`、`NoReconnectOrReplay` 均通過。Commit `feat: execute MSSQL import batches with explicit outcomes`。 +- [x] **Step 1: 先寫失敗的 fake-session tests。** `DefaultStopsAtFirstError`、`SkipContinuesOnlySafeBatch`:未勾後續0calls;勾選一般class11–16、前後交易0/XactState0、same DB、無LOB pending、log flush成功才下一批。任何 SqlError 嚴重/timeout/傳輸/不明 outcome 不可 skip,不比對 message 語言。`FlushFailsBeforeSkip` 注入真實log flush fault,斷言 `NextBatchCalls==0`。 +- [x] **Step 2: 實作預檢→確認→執行流程。** 所有 input encoding/batch/native/目標/log 可寫性問題於第一個 DB write 前阻擋,parser失敗時execution factory calls=0;不同檔案/target/skip設定令預檢失效,ReusedPreflightIsRejected 測試第二次 Run 不送 SQL。一次一批,結果與 state 查明後才確認 bytes;目前batch可能部分生效,分開成功、失敗與未知批次。 +- [x] **Step 3: 實作 native batch role/state gate 及 EOF。** native LOB initialization/assemble/commit 任一 error fatal,即使 XACT_STATE0;普通batch遇錯也查已初始化 native state。每個走到 EOF 的作業都查交易、identity、digest、LOB唯一state/Failed0/Consumed1/Sequence=ConsumedThrough,包含 skip/DataOnly;pending/missing/wrongjob 不得 amber完成。無錯 NativeSchema 才逐表 COUNT_BIG 對 footer tables/rows,核對可取消。 +- [x] **Step 4: 實作取消/cleanup terminal tests。** 先 Stopping、不排下一批;Cancel10秒無回應只關本 session;cleanup10秒限時。自然 EOF 未結交易、取消在成功回應邊界、狀態查詢/COUNT_BIG/log flush 中取消、cleanup未確認都測。已失敗的原始結果不能被 cleanup exception 覆蓋;若最後 log失敗要顯示存檔未完整。 +- [x] **Step 5: 跑 worker filter、提交。** `PartialBatchEffectsAreNotReportedAsRows`、`SkippedRunStillChecksEofState`、`NativeLobPendingAtEofFails`、`NoReconnectOrReplay` 均通過。Commit `feat: execute MSSQL import batches with explicit outcomes`。 ## Task 5: Four-step native wizard、Punky 與 MSSQL routing From ff278598eb422d5f2834a0d24ba849fc15057714 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 13 Oct 2026 23:21:42 +0800 Subject: [PATCH 14/26] feat: add MSSQL SQL import wizard --- .../snapshot/native-confirm-dark-1.5.png | Bin 0 -> 23439 bytes .../snapshot/native-confirm-dark-1.png | Bin 0 -> 25123 bytes .../snapshot/native-confirm-dark-2.png | Bin 0 -> 17395 bytes .../snapshot/native-confirm-light-1.5.png | Bin 0 -> 25217 bytes .../snapshot/native-confirm-light-1.png | Bin 0 -> 27009 bytes .../snapshot/native-confirm-light-2.png | Bin 0 -> 18653 bytes .../snapshot/native-error-log-dark.png | Bin 0 -> 87515 bytes .../snapshot/native-error-log-light.png | Bin 0 -> 93251 bytes .../snapshot/native-progress-dark.png | Bin 0 -> 87515 bytes .../snapshot/native-progress-light.png | Bin 0 -> 89320 bytes .../snapshot/native-stopping-light.png | Bin 0 -> 83930 bytes mySQLPunk/Form1.MssqlImport.cs | 54 ++ mySQLPunk/Form1.cs | 8 +- mySQLPunk/MssqlImportWizardForm.cs | 473 +++++++++++++ mySQLPunk/mySQLPunk.csproj | 2 + tests/Run-SmokeTests.ps1 | 2 +- tests/SmokeTests.MssqlImport.Wizard.cs | 645 ++++++++++++++++++ tests/SmokeTests.cs | 13 + 18 files changed, 1195 insertions(+), 2 deletions(-) create mode 100644 docs/design/mssql-import/snapshot/native-confirm-dark-1.5.png create mode 100644 docs/design/mssql-import/snapshot/native-confirm-dark-1.png create mode 100644 docs/design/mssql-import/snapshot/native-confirm-dark-2.png create mode 100644 docs/design/mssql-import/snapshot/native-confirm-light-1.5.png create mode 100644 docs/design/mssql-import/snapshot/native-confirm-light-1.png create mode 100644 docs/design/mssql-import/snapshot/native-confirm-light-2.png create mode 100644 docs/design/mssql-import/snapshot/native-error-log-dark.png create mode 100644 docs/design/mssql-import/snapshot/native-error-log-light.png create mode 100644 docs/design/mssql-import/snapshot/native-progress-dark.png create mode 100644 docs/design/mssql-import/snapshot/native-progress-light.png create mode 100644 docs/design/mssql-import/snapshot/native-stopping-light.png create mode 100644 mySQLPunk/Form1.MssqlImport.cs create mode 100644 mySQLPunk/MssqlImportWizardForm.cs create mode 100644 tests/SmokeTests.MssqlImport.Wizard.cs diff --git a/docs/design/mssql-import/snapshot/native-confirm-dark-1.5.png b/docs/design/mssql-import/snapshot/native-confirm-dark-1.5.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e8bd049ed03685540eeafd528aca60dc748242 GIT binary patch literal 23439 zcmdSB2~?9=);6l2{T0<+t+caYPI{p@EyhvdIpMeP2=(Le0iv17OM<%`#L?D&uS;79M%Prz@?1R-?r-_FQu zh(GUO_8*gii{IhDb^Uh74tC~e>wf! zMm`?@w)qx%IDV_B*T8xz;H-(+o2aT4?iR7++rP69p8Mt-_dlio{_oRi?PkBf*&A@q z>jDAqgRM?d#SwQHU-0WDk$4*hZcQEb9R@cH|S-S=Cx`H)B8 z&TE8S(=3j%4t#w2aMx2)=f>&HHp7Vv8*^^!lPkMen@_B393rD@HQ{>|CRMiIY-*ce zH;CG*mUwMS8I;txG<))Dop0RyN&((6tWmN^D$PxpvU8hQI+I9goXztt%@3=OY?L!e zr9G_rn~m}=to``%BP^8MRTMY8(v~>+o}dHovC+3BEppvj7K-gRW|Lsir8n@*el^Tu zk{lrTq|=V8n|gLZp`Cy5#j-t*xVch!c;jbjpry87Dr=c1l$K%YagA#2g;E)-A--|` z7w<9>S9NLVk)0R@-OLe{iLf7DNwadX)*I}tg%(edTej&fm0OE=^C!2fEh~l)$Ln-! z4?GEScnNkkRj)HYjNHBQm~MHc4!fEnUE^unr8)TuDwU|YUKYFlpoqHIct;X7Vq@o; zNqmbd1w$|x+8yf{OZ+>j4Jwz4gKxBHT^wknDWDayM=d6cyZh{MO; zAcN%fL2vl55B$JZ`b+1&6&NUJJw1y3B^(Tn%JvuO}ej!(uLy= z(8ccjGDBulsP?)WWpw42qOB2WE@k#)nPO8AMy19nf0kOsjzPzXy6a^K=w$d%Vm!ZQ zD6md!LmtV6-wthgBy8DKeK*`eY1jOkfK4zq(Tw%DWJh5N{&+=`NYo0$bRV906*f4K zq~zvFJ{$(sHCWDj@!59S;tsL~zOtpSnrEy2AT2ZNj)RkIhx3S=M zbxV;n0o!;@r~E)%s-jx?)-TUXwT6oY%(&j@A(V%&HFR>+u*{OYIz!M^Fg|&vwn{}g z$!13lB6|@wNb@0B=4EfYzv?tAM3N4{zFd=J>I`MAW+gguWSeeoEz231)aU#s^r~EO zN3fahE`0Sa6J{=bCwjFoh!{Oigu-Ki=WGq*Hs>Mi0k{cv?6(B8SNWp)K;JIL0m$$ z&GE&nOgtyN5mrnS#(S^qr_={ONn4AaP*g?`=yk>B2mICk&A;mEw}ysT+^M?nT|T+2 zb`o#Ac_$EeG{KjjNOvn%=T?5HV{IlT#?LLiMwDUWJM}j!Qd=h>o9`hMOf`mIxWLwK zIp17_8(<(>?4HdxT)MSL*U12GVQEwEdk^1m{z@c^GPAN|2b@3^Yn48vaoqaPA@5Bo z{4qtr38RWvTDHQ5IF@U*(kAShuq<&?3n^qa&Cg2JhGF^QO&r{DV_1_ov2q+s92upY zR{qFmmdLs-=A9x@MtwEP$fvcpf2U!&t4bPZx1G~XogZz#<;Jg}Lb2-2%a#AsEM@Vo zw5anTr)zcv=-{WQHTG(!*>7VuU=)HDRewY`ED^$2OyJ=W{fezk1qHl*Op6uE7!h9zvRlp|o2#*I=@ng04+q1(jT8Oz7qRX11!*hBmsuMqxjeC+e! z?Ux}{a)UAlhRbQO=REl7f?n2lYU0=Z>vP5nxu!-L9?i27u#Z=Ml?o?R$%Cg8r%wuh zsp+I;aI$_g$N4lKMO}6BhOngJ3K634*Y)l*yjnQp9vpnC

U57#*^u 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 AF#rGn literal 0 HcmV?d00001 diff --git a/docs/design/mssql-import/snapshot/native-confirm-dark-1.png b/docs/design/mssql-import/snapshot/native-confirm-dark-1.png new file mode 100644 index 0000000000000000000000000000000000000000..cbc5c457db0ccf35c7a87fed8287adf008d7905c GIT binary patch literal 25123 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 -RgTqDht#Oq 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 literal 0 HcmV?d00001 diff --git a/docs/design/mssql-import/snapshot/native-confirm-light-1.png b/docs/design/mssql-import/snapshot/native-confirm-light-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f7669d8f24c60e519edebd1119ac5a2f782d2a73 GIT binary patch literal 27009 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 S*Cs9b?mLQ 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 M+rNwZ*`dGvFPpUhi~s-t literal 0 HcmV?d00001 diff --git a/docs/design/mssql-import/snapshot/native-error-log-dark.png b/docs/design/mssql-import/snapshot/native-error-log-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..486f6cdb248ee6097ff3ceae8d08be4b1e8e32e6 GIT binary patch literal 87515 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%0Aw=?Y)AV?VT~to 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 literal 0 HcmV?d00001 diff --git a/docs/design/mssql-import/snapshot/native-error-log-light.png b/docs/design/mssql-import/snapshot/native-error-log-light.png new file mode 100644 index 0000000000000000000000000000000000000000..70738ed1f01ff419e5423f26082d346c0736f1b0 GIT binary patch literal 93251 zcmeEuby$>J*SDgCbPtjO(yf3r5<@rA9ZEOSAsqul2!eDCAtgvjN`nCmEdvY;HFS4< zqn>k~^Su9l-}m2pUo#go_r<>V+H0@%Te&AjLroqJn-crZojZ7n3bI;v?%X%NbLSoz z76$5$Qp~~<>d##dEqUoXRYTP4s4w?zq*SHu+^I>xxw1eMbF-|?ZKqmYE@N9s@H6)*pJ6zT(Il8!@1q63E}Fl}j>JVxWl1$vrruCw{S=g3Ix#^&}&3mE#(`f$7X={cMJ^ZmPK z;xh^T5K)`<&`oFGgJ?OCVo%4M{?6z%B916B<9V|S;H>AmINFLp+v0H=1N8@Kc-1`( z6Rmi@F!_bnB&$W&`wOR}48||;+B!pAfh_k$Udy@L3leL2;KS(t#n)q-nYgw6)mf%9 z&+TGH%JuZo8edvW#vJ(yYF*cJ^Phc9Y@8dM0F#Ro%Fz8no-b$6H7j$IXD=eK7d!!9 zw)eVM9~4~FK|lH(T0B^03`V+^9^=<-Cwflb{A# zFT%G+sStP^gq_Hc43s;RpKDHn0@Y$U|VFR)Gv`Sw6uNhP%wWxDWOj94$mmvhR@5d zUQ4VlG?4C#S+1bAD(YKD998BgLII}Kz2;C}qwBq=f4L(aK)wk7q&c%%{^ijh}zSD-rt`^OI%wth0FVV-lp z&F^nHzx!F;k8D_mlIKUDP0+Z+s=U*%nfJ7B&sUTzCFll_J$wK8m9f`F8O22K9bCC* zp*y_HVBvdo632um0S#DBOH8Al`n?7Y*hj&%vBIF}nLqBPj)5wuuTgX}kdYUdS=IL{ z%k%^LB%^kSP)Cv~g!=IZ@< z1fD$qC?CY?*@;*YL*LEyQq z2=!k~@8@{dtLhht0Z5RbAyCf_XK=aOOsa#B94oOHt4MRzg_{mQVHRFzBcGZGo#nCU zgXtxjb_H>fv*-`(e51D2V~-e30(i*L3i??g?Kk>M8!%malEzeqoR-lnWP|>$RlJKr z&;GF!M|})TiKsss_Kz~Ej4=WzBw(S!pl8%j&Pzv7z?RIA)!bD2r?bN*JC#l#Y6&kp z$V3W;t$to`rMLOqd&OgTdt2=;xX=cFay}W>n|cou|B4pkWS7;N(5rd4VmW*fcJ9eur&RQasIBry!t^H24R0ItOijhwartR%4DD26 z^kqVt&l1%Pz{S|A?>|VP3Nki7tGJQw&&`H(kWt_ZCmb8`o{sS#n41@f12@$kLjw`U z5Ls-=sNDXwbjD?K7@)%i?g~>m7rH#z7Uk4x8NaBX5wt~{ zCF#yeJUa1vr@~AE$QXxWo=KV_;_YnBTHO#?`iChe(2<5n=K0yklU}N+5x%5d`pHxJ z2GBL$T$E7m-%z`%|Fvj+*!(=wW$$K`XX({fCjuJXS&i6Vf=2oaq^SI9NBJ6@=h)@_ z;3Mt&F}}3QMg6=kDNnuE0q#YD=Q{Rj7io??DezeCq$N2pSN*ModXRWi^(}m@Q?{Y^ zFgg_l!8nu7F;t+=NP03z`gyg##r6!1vZN2mbS=JQrRkfwZxTK2>hoytzITeJnMSu# zi^oa>g)Ya51|~A{YcKF&xuom;?nnM^M$|maPm1ZS7?)D|*z4Jjd#PB4%6RbJGlGdo zTvRFoS^v7HNl8`B6;=2$@E@5J_NO!bH%p4 z=1g@HO*zlJkef<{9^@3U79XS|0*{oltNL@BuLfL53JL5NsS63_4EHvln>;?*hqE!(epW zm&Dq|bgc+^vErt{rK705#e?d-kfRiOyWCNUrGMAr=f239%l7Y(U1Jx-8ltAfVVA<^2obT5b?q~;$??6)tn z?Eb*hE?RNt5wn&`DbJ`7O74CcQ0J<({rwNssP~UEpOseuwHxLVrso0@2CsRwBMuWA zAi~Nz17sO#v_-r;#1nkW8(Ehf&X3>18-7UyEHDKZ)A znnETG8SPv??lPm6ehKHM;LRf^8QP3`PZr^K)Nc^q#xMKkf*8^sUD+K9{ zew#$`o+|6pKaRy#tAA3ax&$eE!gM(`Y%c?6XKr&FpU>ZH>*RR58V$KPp}eMFZUDsW zityQMo19pLX=*9b07O*iZ*`X5&bn@Z>7Yt>6mq9HK?0A*So|(}dqBz&GCrBA zaB%ybHD^MR)NDllvAoK1v8e=dP!eMyVX zi0D68X-v<>gZ~UreLShI?@G_`=dx$03F->P`D>siNz5?`x$$2EqcapLaz8Fe|25ON ztmSn$I^eH?13^sEzhi9Lt4Hb%$sTpl-tGGrf9(KR=NHSUo6-f|IgNIdN53?gJVNMXI93u;NqhtlQJ#_ zQ!`G)8FG8T-%W)R(d4s6GRFc2P0SOfH1@Vf+9Ij<&k%f8z$_kT4xpXb-!wC!XwC>#4wP)Y zMN&W-E~0@UNI^)?p?sg*JZM|VE?QFLCV@DCWk-FM`7e3j>A6t+#M7kELx)t_*i2)M z*R%(*Tp0H-ga}nh)SNIj!~`O|JX?f{B@nY0J)*^0vX&hbZn%GDghHQJLUMLFO_C74ec1%30b|H8p@V6wpc|c~*%8OzB(wY> zIee7h7PD!VVI?eb#uQ#=@A(8^(UXWpA|A-?D&VdA(f9(WH

!PuIUBOrVz|Ew8Nkdu#sU73=i^_*h14GQktl z5bYCKBbxvK-Ltfe*#Y#&!Yo^+c^W`Oz4i&@E^*T=v^?`QOqLy^m--$te+bB6M2Y1K zQsbU+d1^Wrl%JXJQ2+9@^0O3eCn{HWtai!#y=Z;ZqBCB105_1I3|68ryNAEP1tW>7txJInI9w9nBxR@ zh!>;*YacUANOu;jVXtQo(hvcUUfL=-K~pYLPs&pym1RzK;7!OIeXBxAJE>uR+Y}rD3DCqKzJG+oU4_*6@%{`IF%u$Pf9di5#bc%G-(*m^bK@}u zHTaaN2U_(6xfwZXi!_Wm91B$#|0X zTXbxHS$GsCo>|dPCZr>S_>`;)FMAp;h*h_=V}))KzB|N5?r_WtLE0~75P_5WsAyl5 z!4Hn-8&5ba!xmf|xutHW(&`a|GBA?fN7FusDLs@tL1uWu??%&YYi2SF=r0`ygr60u z{@S?`e&!6V7N0mD%?uKhCM^9Z`%8ByQPw~OV9dY}h>$#^x=6UaxVSC7IN>;v4+b;l z^PzOMfo~g{tG@11$j>5Ore3DX5R`zZ>2Y#1e89;>n3}So>u=fhg@5B>+H9 zp_2HNluSyOy2RD$#O0Es+&RjDYsY$8BE?#nk4;;AZV+q4mxcYTzZQJivlQFoq470I z7tXhNsRHd8)`T0o83$G;om%$PDD@}vH(Xbf?>3?2h6bg&@*9`Yv?MM86&}R>(Uw27 zDV2XyP(irK@}psafhd?XT9dLw_6oB@OBTAVbeP(+QC=->ni9Q@_uk{NES-@UOO3i> z#feW(AVA3yQgFDH2hmD7gbdb0rTxq#*ZeW>QTH+2RxC$zcrJN|yC>4{E?% z4Io$n<8fdQOfPU7T5XxqC*K$Yv!wc^vCx`d?u!6=nm*-I=E>>48}sP8iD&AMQQ3zA z{cC8h{FNh~a6*TY44BGAWqFn=dEhKki?Y0qZvUF@N78uWl7MwwX}fSzkejhgdlXW_ z&A8&TrI8HyP|snYhDub9nr`!HtkZEI-Tnnb%8*Q!HoT#%Pc|6<_L z@GlY0_)oavfpP%Oj19$@TJ+w za-(aXZBooSNT3gV=6|x&eUdHtG(P$$n?`7_{Oq+BuH{`wjd1cWi)P^Ze$7*my@ua9 zPIlI;l~ogEL&}Hg-j8V@)(9oFTdhF3;`7tC2%&u+%V3!qt7DR10xU2I-WGK`PSw`X z7{}}E+7UV}DBs^YH^se_;Tw~%dw9t8(kGxh*dS z*Dq6->ATWYf?F-Oq3ji`$B7BCM&5ygNKVCL73-I?{93e%YBB^j1T7*!KrJV-@cC_b~A z_)w2XwE8;Sa$^3i5%$r4*t7;jX}8;M_VKudZe=&clH~8*1#g5ZANki*=J(JYtLE3` z7H^qlu{htpPigN*wj=eDgr4d42qP|$Zb}|0s6Ybt+cf1`?9KZVaEmPikb?cc0ap6lcZ^46~b2sdHrAsDw8ol#`fL;X9 zzx>a>o467MTlXu8;XPzLFSIH+<;l?tTw_JSDISr_Ep&qlP~MU61hou2K|0m&G^


`JoZGhN<; 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 fg09gmu1SG^8~e%nb~6W8eHw13SXM literal 0 HcmV?d00001 diff --git a/docs/design/mssql-import/snapshot/native-progress-dark.png b/docs/design/mssql-import/snapshot/native-progress-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..486f6cdb248ee6097ff3ceae8d08be4b1e8e32e6 GIT binary patch literal 87515 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%0Aw=?Y)AV?VT~to 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 literal 0 HcmV?d00001 diff --git a/docs/design/mssql-import/snapshot/native-progress-light.png b/docs/design/mssql-import/snapshot/native-progress-light.png new file mode 100644 index 0000000000000000000000000000000000000000..1a0f432d8eac01ba739f239488a25426e7574154 GIT binary patch literal 89320 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

z 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 NyzM3Ri?9Foe*%Cz=L7%% literal 0 HcmV?d00001 diff --git a/docs/design/mssql-import/snapshot/native-stopping-light.png b/docs/design/mssql-import/snapshot/native-stopping-light.png new file mode 100644 index 0000000000000000000000000000000000000000..91d15907208e187846dfc3eac41a984eabd7f4ce GIT binary patch literal 83930 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

3!f#d8Egt| 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, MssqlImportRequest, MssqlImportResult> MssqlImportWizardRunner; + internal Func SqlImportOpenDialogRunner; + internal Action MssqlImportStatusSink; + private static bool IsMssqlImportTarget(TreeDatabaseTarget target) => target != null && + (string.Equals(target.ProviderName, "mssql", StringComparison.OrdinalIgnoreCase) || string.Equals(target.ProviderName, "sqlserver", StringComparison.OrdinalIgnoreCase)); + private DialogResult ShowSqlImportFileDialog(OpenFileDialog dialog) => SqlImportOpenDialogRunner == null ? dialog.ShowDialog() : SqlImportOpenDialogRunner(dialog); + private void SetMssqlImportStatus(string text) { if (MssqlImportStatusSink == null) UpdateMainStatus(text); else MssqlImportStatusSink(text); } + private void OpenMssqlImportWizard(TreeDatabaseTarget target) + { + try + { + var settings = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var pair in target.ConnectionInfo) + { + if (string.Equals(pair.Key, "pdo", StringComparison.OrdinalIgnoreCase) || string.Equals(pair.Key, "isConnect", StringComparison.OrdinalIgnoreCase) || string.Equals(pair.Key, "connString", StringComparison.OrdinalIgnoreCase)) continue; + if (pair.Value == null || pair.Value is string || pair.Value.GetType().IsPrimitive || pair.Value is decimal) settings[pair.Key] = pair.Value; + } + settings["db_kind"] = "mssql"; settings["provider"] = "mssql"; settings["initial_database"] = target.DatabaseName; + var initial = new MssqlImportRequest(Guid.NewGuid(), "", target.DatabaseName); + MssqlImportResult result; + if (MssqlImportWizardRunner != null) result = MssqlImportWizardRunner(settings, initial); + else + { + using (var wizard = new MssqlImportWizardForm(initial, () => new MssqlImportService( + () => new MssqlImportSqlSession(ConnectionOpenService.OpenMssqlImportSession(settings)), job => new MssqlImportLog(job)))) + { wizard.ShowDialog(this); result = wizard.Result; } + } + if (result == null) return; + string text; + switch (result.Status) + { + case MssqlImportStatus.Completed: text = ReportText.Get("SQL Server 匯入執行完成", "SQL Server import execution completed"); break; + case MssqlImportStatus.CompletedWithErrors: text = ReportText.Get("SQL Server 執行完成,但有錯誤/部分寫入", "SQL Server completed with errors/partial writes"); break; + case MssqlImportStatus.Cancelled: text = ReportText.Get("SQL Server 匯入已取消;先前寫入可能保留", "SQL Server import cancelled; previous writes may remain"); break; + case MssqlImportStatus.CleanupUncertain: text = ReportText.Get("SQL Server 匯入/清理狀態未確認", "SQL Server import/cleanup unconfirmed"); break; + default: text = ReportText.Get("SQL Server 匯入停止:發生錯誤", "SQL Server import stopped: error"); break; + } + if (!string.IsNullOrWhiteSpace(result.LogPath)) text += " · " + result.LogPath; + SetMssqlImportStatus(text); + } + catch (Exception) { SetMssqlImportStatus(ReportText.Get("無法開啟 SQL Server 匯入精靈,請確認已選目標。", "Cannot open SQL Server import wizard; review the selected target.")); } + } + } +} diff --git a/mySQLPunk/Form1.cs b/mySQLPunk/Form1.cs index 4617393..9bae155 100644 --- a/mySQLPunk/Form1.cs +++ b/mySQLPunk/Form1.cs @@ -7334,6 +7334,12 @@ private async void ImportSqlWithDialog() return; } + if (IsMssqlImportTarget(target)) + { + OpenMssqlImportWizard(target); + return; + } + MySqlImportOptions mysqlOptions = null; if (IsMySqlTarget(target)) { @@ -7347,7 +7353,7 @@ private async void ImportSqlWithDialog() dialog.Filter = Localization.T("Common.SqlFilesFilter"); dialog.Multiselect = false; - if (dialog.ShowDialog() != DialogResult.OK) + if (ShowSqlImportFileDialog(dialog) != DialogResult.OK) { return; } diff --git a/mySQLPunk/MssqlImportWizardForm.cs b/mySQLPunk/MssqlImportWizardForm.cs new file mode 100644 index 0000000..cf636dc --- /dev/null +++ b/mySQLPunk/MssqlImportWizardForm.cs @@ -0,0 +1,473 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using mySQLPunk.lib; +using mySQLPunk.lib.MssqlImport; +namespace mySQLPunk +{ + internal sealed class MssqlImportWizardForm : Form + { + private readonly Func serviceFactory; + private readonly string database; + private readonly Panel[] pages = new Panel[4]; + private readonly TextBox source = new TextBox(), target = new TextBox(), logPath = new TextBox(), errors = new TextBox(); + private readonly CheckBox skip = new CheckBox(), confirm = new CheckBox(); + private readonly Label steps = new Label(), status = new Label(), facts = new Label(), checkSummary = new Label(), confirmSummary = new Label(); + private readonly Label stage = new Label(), coverage = new Label(), position = new Label(), elapsed = new Label(), eta = new Label(), errorCount = new Label(), resultText = new Label(); + private readonly Button next = new Button(), back = new Button(), recheck = new Button(), cancel = new Button(), browse = new Button(), mute = new Button(); + private readonly Button openLog = new Button(), openFolder = new Button(), copyPath = new Button(); + private readonly ProgressBar bar = new ProgressBar(), scanBar = new ProgressBar(); + private readonly PunkyReportLoadingControl punky = new PunkyReportLoadingControl(), confirmPunky = new PunkyReportLoadingControl(); + private readonly System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer { Interval = 200 }; + private readonly Stopwatch clock = new Stopwatch(); + private readonly object progressGate = new object(); + private MssqlImportProgress latest; + private MssqlImportPreflight prepared; + private MssqlImportRequest request; + private MssqlImportService service; + private CancellationTokenSource cancellation; + private Task cancellationDispatch; + private bool acceptingProgress, terminalRendered; + private long confirmedBytes, lastAdvance, fileBytes; + private int generation, step; + private Guid activeJob; + private bool busy, executing, closing, cancelRequested, disposing; + internal MssqlImportResult Result { get; private set; } + // Instance action boundaries prevent native tests from launching apps or changing the clipboard. + internal Action PathOpener; + internal Action ClipboardWriter; + private static string T(string zh, string en) => ReportText.Get(zh, en); + internal MssqlImportWizardForm(MssqlImportRequest initialRequest, Func serviceFactory) + { + if (initialRequest == null) throw new ArgumentNullException(nameof(initialRequest)); + this.serviceFactory = serviceFactory ?? throw new ArgumentNullException(nameof(serviceFactory)); database = initialRequest.DatabaseName; + Name = "mssqlImportWizard"; Text = T("匯入 SQL 檔案 · SQL Server", "Import SQL file · SQL Server"); + AutoScaleMode = AutoScaleMode.Dpi; Font = UiKit.Body; ClientSize = new Size(1100, 750); + MinimumSize = new Size(640, 480); StartPosition = FormStartPosition.CenterParent; + var root = new TableLayoutPanel { Dock = DockStyle.Fill, Padding = new Padding(24), ColumnCount = 1, RowCount = 4 }; + root.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + root.RowStyles.Add(new RowStyle(SizeType.AutoSize)); root.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); + root.RowStyles.Add(new RowStyle(SizeType.AutoSize)); root.RowStyles.Add(new RowStyle(SizeType.AutoSize)); Controls.Add(root); + var header = Stack(); header.Controls.Add(L(T("SQL 檔案匯入精靈", "SQL file import wizard"), UiKit.Title)); + steps.AutoSize = true; steps.Margin = new Padding(0, 12, 0, 16); header.Controls.Add(steps); root.Controls.Add(header, 0, 0); + var body = new Panel { Dock = DockStyle.Fill }; root.Controls.Add(body, 0, 1); + for (int i = 0; i < 4; i++) { pages[i] = new Panel { Name = "importStep" + i, Dock = DockStyle.Fill, AutoScroll = true }; body.Controls.Add(pages[i]); } + BuildSource(initialRequest); BuildCheck(); BuildConfirm(); BuildExecution(); + status.Name = "importStatus"; status.AutoSize = true; status.Margin = new Padding(0, 10, 0, 8); root.Controls.Add(status, 0, 2); + var footer = new FlowLayoutPanel { Name = "importFooter", Dock = DockStyle.Fill, AutoSize = true, WrapContents = true, FlowDirection = FlowDirection.RightToLeft }; + Configure(cancel, "importCancel", T("取消", "Cancel"), (s, e) => { if (busy) RequestCancel(); else Close(); }); + Configure(next, "importNext", T("下一步 →", "Next →"), async (s, e) => { + if (busy || closing || disposing) return; + if (step == 0) await CheckAsync(); + else if (step == 1 && prepared?.Passed == true) { step = 2; ShowPage(); } + else if (step == 2 && prepared?.Passed == true && confirm.Checked) await RunAsync(); + else if (step == 3 && Result != null) await CheckAsync(); + }); + Configure(back, "importBack", T("← 上一步", "← Back"), (s, e) => { if (!busy && step > 0 && step < 3) { step--; ShowPage(); } }); + Configure(recheck, "importRecheck", T("重新檢查", "Recheck"), async (s, e) => { if (!busy && !closing) await CheckAsync(); }); + footer.Controls.AddRange(new Control[] { cancel, next, back, recheck }); root.Controls.Add(footer, 0, 3); + ThemeManager.MarkAsPrimary(next); AcceptButton = next; CancelButton = cancel; cancel.DialogResult = DialogResult.None; + timer.Tick += (s, e) => RenderHeartbeat(); + ClientSizeChanged += (s, e) => { + root.Padding = new Padding(ClientSize.Width < 800 || ClientSize.Height < 600 ? 12 : 24); + steps.MaximumSize = new Size(Math.Max(180, root.ClientSize.Width - root.Padding.Horizontal), 0); status.MaximumSize = steps.MaximumSize; + foreach (var button in new[] { next, back, cancel, recheck }) { button.Margin = new Padding(3); button.MinimumSize = new Size(85, 32); } + Reflow(); + }; + Shown += (s, e) => { + var work = Screen.FromControl(Owner ?? this).WorkingArea; + MinimumSize = new Size(Math.Min(MinimumSize.Width, work.Width), Math.Min(MinimumSize.Height, work.Height)); + Size = new Size(Math.Min(Width, work.Width), Math.Min(Height, work.Height)); + Location = new Point(Math.Max(work.Left, Math.Min(Left, work.Right - Width)), Math.Max(work.Top, Math.Min(Top, work.Bottom - Height))); Reflow(); + }; + FormClosing += (s, e) => { if (busy) { e.Cancel = true; closing = true; RequestCancel(); } else DiscardPrepared(); }; + ThemeManager.ApplyTo(this); ShowPage(); + } + private static FlowLayoutPanel Stack() => new FlowLayoutPanel { Dock = DockStyle.Top, AutoSize = true, FlowDirection = FlowDirection.TopDown, WrapContents = false, Margin = Padding.Empty }; + private static Label L(string text, Font font = null) => new Label { AutoSize = true, Text = text, Font = font ?? UiKit.Body, Margin = new Padding(0, 6, 0, 8) }; + private static void Configure(Button b, string name, string text, EventHandler handler) + { b.Name = name; b.Text = b.AccessibleName = text; b.AutoSize = true; b.MinimumSize = new Size(90, 34); b.Margin = new Padding(3); b.Click += handler; } + private void BuildSource(MssqlImportRequest initial) + { + var content = Stack(); pages[0].Controls.Add(content); + content.Controls.Add(L(T("把 SQL 檔案,帶進目標資料庫", "Bring a SQL file into the selected database"), UiKit.Subtitle)); + content.Controls.Add(L(T("先選檔案,再串流檢查;預檢不執行檔案中的 SQL。", "Choose a file, then check it by streaming. Preflight does not execute its SQL."))); + source.Name = "importSourcePath"; source.Text = initial.SourcePath; source.ReadOnly = true; source.Width = 800; + source.AccessibleName = T("SQL 檔案完整路徑", "SQL file path"); source.TextChanged += (s, e) => { InvalidatePrepared(); ReadFileSize(); }; + content.Controls.Add(L(T("SQL 檔案", "SQL file"))); content.Controls.Add(source); + Configure(browse, "importBrowse", T("選擇檔案…", "Choose file…"), (s, e) => { + if (busy) return; + using (var dialog = new OpenFileDialog { Filter = Localization.T("Common.SqlFilesFilter"), Multiselect = false, CheckFileExists = true }) + if (dialog.ShowDialog(this) == DialogResult.OK) source.Text = dialog.FileName; + }); content.Controls.Add(browse); + facts.Name = "importFileFacts"; facts.AutoSize = true; content.Controls.Add(facts); + target.Name = "importTarget"; target.ReadOnly = true; target.Width = 800; + target.Text = T("已選資料庫:", "Selected database: ") + database + T(";實際伺服器識別將於預檢顯示。", "; resolved server identity appears after preflight."); + target.AccessibleName = T("已選目標資料庫", "Selected target database"); content.Controls.Add(L(T("目標 · 使用目前資料庫樹的連線設定", "Target · existing selected connection"))); content.Controls.Add(target); + content.Controls.Add(L(T("更換目標請關閉此精靈,於資料庫樹選擇另一個資料庫後重新開啟。", "To change target, close this wizard and select another database in the tree."))); + content.Controls.Add(L(T("支援 mySQLPunk 匯出 SQL 與一般 T-SQL/GO;嚴格偵測 UTF-8,或有 BOM 的 UTF-16。單一 GO 批次上限 32 MiB(16,777,216 個 UTF-16 code unit),不是欄位大小限制。", "Supports mySQLPunk SQL and ordinary T-SQL/GO; strict UTF-8 or BOM-marked UTF-16. One GO batch is limited to 32 MiB decoded (16,777,216 UTF-16 code units), not a field-size limit."))); + content.Controls.Add(L(T("不支援 SQLCMD 指令或直接 USE 切換資料庫。三段名稱、動態 SQL 或程序仍可能存取其他資料庫,請確認腳本來源。精靈不會自動建立、清空或覆寫資料庫。", "No SQLCMD directives or direct USE changes. Three-part names, dynamic SQL and procedures can still access other databases; review the script source. No automatic database creation or clearing."))); ReadFileSize(); + } + private void BuildCheck() + { + var content = Stack(); pages[1].Controls.Add(content); + content.Controls.Add(L(T("先確認,這份檔案能不能匯入", "Check the file and target before importing"), UiKit.Subtitle)); + content.Controls.Add(L(T("完整串流預掃描:編碼、GO 批次、格式摘要、目標與 log 可寫性。這是分析進度,尚未執行 SQL。", "Streaming preflight checks encoding, GO batches, format summary, target and log writability. No source SQL has executed."))); + scanBar.Name = "importScanProgress"; scanBar.Width = 800; scanBar.Height = 10; content.Controls.Add(scanBar); + checkSummary.Name = "importCheckSummary"; checkSummary.AutoSize = true; checkSummary.Text = T("尚未開始檢查。", "Not checked yet."); content.Controls.Add(checkSummary); + } + private void BuildConfirm() + { + var content = Stack(); pages[2].Controls.Add(content); + content.Controls.Add(L(T("準備好,開始匯入這份資料", "Review before starting this import"), UiKit.Subtitle)); + confirmSummary.Name = "importConfirmSummary"; confirmSummary.AutoSize = true; content.Controls.Add(confirmSummary); + skip.Name = "importSkipErrors"; skip.AutoSize = true; skip.Text = T("遇到 SQL 錯誤時,略過失敗 GO 批次並繼續(變更後須重新檢查)", "Skip failed GO batches on eligible SQL errors (recheck after changing)"); + skip.AccessibleName = skip.Text; skip.Checked = false; skip.CheckedChanged += (s, e) => InvalidatePrepared(); content.Controls.Add(skip); + content.Controls.Add(L(T("略過不會撤回該批已生效的語句。timeout、斷線、交易/LOB 狀態不明及 log 寫入失敗仍停止。", "Skipping does not undo statements already applied. Timeout, disconnection, uncertain transaction/LOB state and log failures still stop."))); + confirm.Name = "importConfirmTarget"; confirm.AutoSize = true; confirm.Text = T("已確認目標資料庫,並了解異常時可能保留部分資料。", "I confirm the target and understand that partial writes may remain."); + confirm.AccessibleName = confirm.Text; confirm.CheckedChanged += (s, e) => UpdateButtons(); content.Controls.Add(confirm); + confirmPunky.Name = "importConfirmPunky"; confirmPunky.Size = new Size(200, 200); content.Controls.Add(confirmPunky); + } + private void BuildExecution() + { + var content = Stack(); pages[3].Controls.Add(content); + stage.Name = "importStage"; stage.Font = UiKit.Subtitle; coverage.Name = "importCoverage"; position.Name = "importPosition"; elapsed.Name = "importElapsed"; eta.Name = "importEta"; + resultText.Name = "importResult"; resultText.AutoSize = true; resultText.Visible = false; + var statsRow = new TableLayoutPanel { Name = "importStatsLayout", AutoSize = true, ColumnCount = 2, RowCount = 1, Width = 1000 }; + statsRow.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 72)); statsRow.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 28)); + var stats = Stack(); statsRow.Controls.Add(stats, 0, 0); content.Controls.Add(statsRow); + foreach (var label in new[] { stage, coverage, position, elapsed, eta }) { label.AutoSize = true; label.Margin = new Padding(0, 4, 0, 4); stats.Controls.Add(label); } + bar.Name = "importProgress"; bar.Width = 650; bar.Height = 10; stats.Controls.Add(bar); + var mascot = new FlowLayoutPanel { AutoSize = true, WrapContents = true, FlowDirection = FlowDirection.LeftToRight }; + punky.Name = "importPunky"; punky.Size = new Size(160, 160); mascot.Controls.Add(punky); + Configure(mute, "importMute", T("靜音", "Mute"), (s, e) => { punky.Muted = !punky.Muted; mute.Text = mute.AccessibleName = punky.Muted ? T("開啟聲音", "Unmute") : T("靜音", "Mute"); }); + mute.Enabled = punky.AudioAvailable; mute.AccessibleDescription = T("每次實際執行只在首輪播放一次;取消靜音不會重播。", "Sound plays once per execution job; unmuting never replays it."); mascot.Controls.Add(mute); + statsRow.Controls.Add(mascot, 1, 0); content.Controls.Add(resultText); + content.Controls.Add(L(T("錯誤紀錄 · 最近預覽與本機 log", "Error log · recent preview and local log"), UiKit.Subtitle)); + logPath.Name = "importLogPath"; logPath.ReadOnly = true; logPath.Multiline = true; logPath.WordWrap = true; logPath.ScrollBars = ScrollBars.Vertical; logPath.Height = 42; logPath.Width = 800; logPath.AccessibleName = T("完整 log 路徑", "Full log path"); content.Controls.Add(logPath); + errors.Name = "importErrorText"; errors.ReadOnly = true; errors.Multiline = true; errors.ScrollBars = ScrollBars.Both; errors.WordWrap = false; errors.Width = 800; errors.Height = 115; errors.MaxLength = 32768; + errors.AccessibleName = T("最近錯誤紀錄(唯讀)", "Recent errors (read only)"); content.Controls.Add(errors); + errorCount.Name = "importErrorCount"; errorCount.AutoSize = true; content.Controls.Add(errorCount); + var actions = new FlowLayoutPanel { AutoSize = true, WrapContents = true }; + Configure(openLog, "importOpenLog", T("開啟 log", "Open log"), (s, e) => OpenLogPath(false)); + Configure(openFolder, "importOpenFolder", T("開啟資料夾", "Open folder"), (s, e) => OpenLogPath(true)); + Configure(copyPath, "importCopyPath", T("複製路徑", "Copy path"), (s, e) => { + if (!HasLog()) return; + try { if (ClipboardWriter != null) ClipboardWriter(logPath.Text); else Clipboard.SetText(logPath.Text); status.Text = T("已複製 log 路徑。", "Log path copied."); } + catch (Exception) { status.Text = T("無法複製路徑,請選取上方完整路徑手動複製。", "Cannot copy; select the full path above and copy it manually."); } + }); actions.Controls.AddRange(new Control[] { openLog, openFolder, copyPath }); content.Controls.Add(actions); + } + private void ReadFileSize() + { + fileBytes = 0; try { if (File.Exists(source.Text)) fileBytes = new FileInfo(source.Text).Length; } catch (Exception) { } + facts.Text = fileBytes.ToString("N0") + T(" bytes;編碼與來源摘要待預檢。", " bytes; encoding and source summary await preflight."); UpdateButtons(); + } + private void Reflow() + { + foreach (var page in pages) + { + int width = Math.Max(180, page.ClientSize.Width - 28); + foreach (Control container in page.Controls) + { + container.MaximumSize = new Size(width, 0); + foreach (Control c in container.Controls) + { + if (c is Label || c is CheckBox) c.MaximumSize = new Size(Math.Max(160, width - 8), 0); + if (c is TextBox || c is ProgressBar) c.Width = Math.Max(160, width - 8); + if (c is FlowLayoutPanel) c.MaximumSize = new Size(width, 0); + if (c.Name == "importStatsLayout") { + c.Width = width; c.MaximumSize = new Size(width, 0); int statWidth = Math.Max(120, (int)(width * .69)); + foreach (var label in new[] { stage, coverage, position, elapsed, eta }) label.MaximumSize = new Size(statWidth, 0); + bar.Width = statWidth; int side = Math.Max(80, Math.Min(160, (int)(width * .23))); punky.Size = new Size(side, side); + } + } + } + } + } + private void ShowPage() + { + for (int i = 0; i < 4; i++) { pages[i].Visible = step == i; if (step == i) pages[i].BringToFront(); } + steps.Text = T("① 檔案與目標 → ② 匯入檢查 → ③ 確認執行 → ④ 執行與結果", "① File and target → ② Checks → ③ Confirm → ④ Run and result"); + if (step == 2) status.Text = T("請確認實際目標與錯誤政策後開始匯入;開始會修改目標資料庫。", "Confirm actual target and policy before starting; execution changes the database."); + confirmPunky.SetRunning(step == 2 && !closing); Reflow(); UpdateButtons(); + } + private void UpdateButtons() + { + if (disposing) return; + next.Visible = step < 3 || !busy && Result != null; + next.Enabled = !busy && !closing && (step == 0 ? !string.IsNullOrWhiteSpace(source.Text) && !string.IsNullOrWhiteSpace(database) : step == 1 ? prepared?.Passed == true : step == 2 ? prepared?.Passed == true && confirm.Checked : Result != null); + next.Text = next.AccessibleName = step == 2 ? T("開始匯入", "Start import") : step == 3 ? T("重新檢查匯入", "Recheck import") : T("下一步 →", "Next →"); + back.Visible = step > 0 && step < 3; back.Enabled = !busy && !closing; + recheck.Visible = step == 1 || step == 2; recheck.Enabled = !busy && !closing; + cancel.Enabled = !cancelRequested; cancel.Text = cancel.AccessibleName = busy ? cancelRequested ? T("正在停止…", "Stopping…") : T("取消匯入", "Cancel import") : T("關閉", "Close"); + browse.Enabled = source.Enabled = skip.Enabled = !busy && !closing; confirm.Enabled = !busy && prepared?.Passed == true; + bool hasLog = HasLog(); openLog.Enabled = openFolder.Enabled = copyPath.Enabled = hasLog; + } + private void InvalidatePrepared() + { + if (executing || disposing) return; + lock (progressGate) { generation++; latest = null; activeJob = Guid.Empty; } + if (busy) { cancelRequested = true; SignalCancellation(); } + DiscardPrepared(); confirm.Checked = false; Result = null; + checkSummary.Text = T("檔案或錯誤政策已變更,請重新檢查。", "File or policy changed; recheck required."); + confirmSummary.Text = T("舊預檢已失效。重新檢查後,請再確認實際目標。", "Previous preflight is invalid. Recheck and confirm the actual target."); UpdateButtons(); + } + private void DiscardPrepared() + { + var old = prepared; prepared = null; request = null; service = null; if (old == null) return; + try { old.Dispose(); } + catch (Exception) { if (!disposing) status.Text = T("預檢資源釋放時發生異常,請保留 log 並重新檢查。", "Preflight resource release failed; retain the log and recheck."); } + } + private void BeginOperation(MssqlImportRequest current, bool run) + { + busy = true; executing = run; terminalRendered = false; cancelRequested = false; cancellation = new CancellationTokenSource(); cancellationDispatch = null; clock.Restart(); + lock (progressGate) { acceptingProgress = true; latest = null; activeJob = current.JobId; confirmedBytes = 0; lastAdvance = Stopwatch.GetTimestamp(); } + timer.Start(); UpdateButtons(); + } + private void Publish(MssqlImportProgress progress, int version, Guid job) + { + if (progress == null || progress.JobId != job) return; + lock (progressGate) + { + if (disposing || !acceptingProgress || version != generation || activeJob != job) return; + if (progress.ProcessedBytes > confirmedBytes) { confirmedBytes = progress.ProcessedBytes; lastAdvance = Stopwatch.GetTimestamp(); } + latest = progress; + } + } + private bool Current(int version, Guid job) { lock (progressGate) return !disposing && !IsDisposed && version == generation && activeJob == job; } + private async Task CheckAsync() + { + if (busy || closing || disposing) return; + DiscardPrepared(); confirm.Checked = false; Result = null; errors.Text = ""; resultText.Text = ""; resultText.Visible = false; logPath.Text = ""; scanBar.Value = 0; + lock (progressGate) generation++; + var current = new MssqlImportRequest(Guid.NewGuid(), source.Text, database, skip.Checked); int version = generation; + step = 1; checkSummary.ForeColor = ThemeManager.TextColor; checkSummary.Text = T("正在串流分析檔案…", "Analyzing file by streaming…"); status.Text = checkSummary.Text; + ShowPage(); BeginOperation(current, false); var owner = cancellation; var token = owner.Token; + try + { + var value = await Task.Run(() => { + var worker = serviceFactory(); return Tuple.Create(worker, worker.Preflight(current, p => Publish(p, version, current.JobId), token)); + }); + if (!Current(version, current.JobId) || token.IsCancellationRequested || cancelRequested || closing) { + value.Item2.Dispose(); + if (Current(version, current.JobId) && !closing) status.Text = checkSummary.Text = T("檢查已停止,尚未執行 SQL。", "Check stopped; no source SQL executed."); + return; + } + service = value.Item1; prepared = value.Item2; request = current; RenderCheck(prepared); + } + catch (Exception) { if (Current(version, current.JobId)) status.Text = checkSummary.Text = token.IsCancellationRequested ? T("檢查已停止,尚未執行 SQL。", "Check stopped; no source SQL executed.") : T("無法完成預檢,請確認檔案與連線設定後重試。", "Preflight failed. Review file and connection settings and retry."); } + finally { await EndOperation(owner); } + } + private void RenderCheck(MssqlImportPreflight check) + { + string details = ""; + if (check.Scan != null) + { + var scan = check.Scan; fileBytes = scan.FileBytes; scanBar.Style = ProgressBarStyle.Continuous; scanBar.Value = 100; + details += source.Text + "\r\n" + scan.FileBytes.ToString("N0") + " bytes · " + scan.EncodingName + " · " + scan.BatchCount.ToString("N0") + T(" 批次", " batches") + "\r\n"; + details += T("最大批次:", "Largest batch: ") + scan.MaxBatchCodeUnits.ToString("N0") + " UTF-16 code units\r\n"; + details += ScriptSummary(scan) + "\r\n"; facts.Text = details; + if (string.Equals(scan.Script.SourceReadMode, "READ COMMITTED", StringComparison.OrdinalIgnoreCase)) details += T("來源 READ COMMITTED:各表可能來自不同時間點,匯入可能遇到外鍵衝突;完整摘要不保證跨表一致。", "Source READ COMMITTED: tables may reflect different moments; foreign keys may fail. A complete footer does not prove consistency.") + "\r\n"; + } + if (check.Target != null) + { + var t = check.Target; target.Text = t.ServerName + " / " + t.DatabaseName + " · ID " + t.DatabaseId + " · " + t.DatabaseCreateDate.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + details += T("實際目標:", "Actual target: ") + target.Text + "\r\nSQL Server " + t.Version + " · " + (t.Writable ? "READ_WRITE" : "READ_ONLY") + "\r\n"; + details += T("可見使用者物件:", "Visible user objects: ") + (t.MetadataVisible && t.UserObjectCount.HasValue ? t.UserObjectCount.Value.ToString("N0") : T("無法完整確認", "not fully known")) + "\r\n"; + } + details += string.Join("\r\n", check.Issues.Select(i => (i.IsWarning ? T("提醒:", "Warning: ") : T("阻擋:", "Blocked: ")) + Explain(i.Code) + (i.BatchNumber > 0 ? " · " + T("批次 ", "batch ") + i.BatchNumber + T("/行 ", "/line ") + i.Line + " / byte " + i.ByteOffset : ""))); + checkSummary.Text = details; checkSummary.ForeColor = check.Passed ? ThemeManager.TextColor : ThemeManager.DangerColor; + status.Text = check.Passed ? T("檢查通過,尚未執行 SQL。請到下一步確認。", "Preflight passed; no source SQL executed. Continue to review.") : T("有未通過的項目,暫時無法開始匯入。", "Preflight has blocking issues; import cannot start."); + confirmSummary.Text = details + "\r\n\r\n" + T("完整 log:", "Full log: ") + check.LogPath + "\r\n\r\n" + PartialWarning(); + logPath.Text = check.LogPath ?? ""; UpdateButtons(); Reflow(); + } + private static string ScriptSummary(MssqlImportScan scan) + { + var script = scan.Script; + if (script.Kind == MssqlImportScriptKind.Generic) return T("一般 T-SQL/GO;無匯出筆數摘要。", "Generic T-SQL/GO; no export row summary."); + return (script.Kind == MssqlImportScriptKind.NativeSchema ? T("mySQLPunk 結構匯出", "mySQLPunk schema export") : T("mySQLPunk 資料型匯出", "mySQLPunk data-only export")) + " · " + (script.ExpectedTables?.ToString("N0") ?? "?") + T(" 表/", " tables / ") + (script.ExpectedRows?.ToString("N0") ?? "?") + T(" 筆(檔尾預期摘要,非內容證明)", " rows (footer expectations, not content proof)") + " · " + script.SourceReadMode; + } + private async Task RunAsync() + { + if (busy || closing || disposing || prepared?.Passed != true || !confirm.Checked || request == null || service == null) return; + var current = request; var check = prepared; var worker = service; int version = generation; + Result = null; errors.Text = resultText.Text = ""; resultText.Visible = false; step = 3; ShowPage(); BeginOperation(current, true); + var owner = cancellation; var token = owner.Token; stage.ForeColor = ThemeManager.TextColor; stage.Text = status.Text = T("正在執行匯入…", "Import executing…"); + coverage.Text = T("已處理檔案範圍:0 / ", "Processed file coverage: 0 / ") + check.Scan.FileBytes.ToString("N0") + " bytes"; + position.Text = T("目標:", "Target: ") + target.Text + "\r\n" + T("正在確認執行 session,尚未確認任何批次。", "Checking execution session; no batch acknowledged yet."); + elapsed.Text = T("已經過:00:00:00", "Elapsed: 00:00:00"); eta.Text = T("預估剩餘:未知/計算中", "Remaining: unknown / estimating"); + errorCount.Text = T("目前沒有錯誤;完整 log 路徑見上方。", "No errors yet; full log path above."); bar.Style = ProgressBarStyle.Continuous; bar.Value = 0; + punky.BeginExport(); // Only execution starts sound; scanning/navigation uses silent animation. + try + { + try + { + Result = await Task.Run(() => worker.Run(current, check, p => Publish(p, version, current.JobId), token)); + } + catch (Exception) + { + Result = new MssqlImportResult(current.JobId, MssqlImportStatus.CleanupUncertain, check.Scan.FileBytes, + logPath: check.LogPath, validationSummary: "UnexpectedWorkerFailure;CleanupUnconfirmed"); + } + // Rendering cannot replace an authoritative worker result with a synthetic outcome. + if (Current(version, current.JobId)) { RenderHeartbeat(); RenderResult(Result); } + } + finally + { + try { check.Dispose(); } + finally { prepared = null; request = null; service = null; await EndOperation(owner); } + } + } + private async Task EndOperation(CancellationTokenSource owner) + { + // Provider Cancel may wait synchronously. Keep the same CTS alive until its dispatch returns. + if (cancellationDispatch != null) { try { await cancellationDispatch; } catch (Exception) { /* Worker result remains authoritative. */ } } + lock (progressGate) { acceptingProgress = false; latest = null; activeJob = Guid.Empty; } + owner.Dispose(); if (ReferenceEquals(cancellation, owner)) cancellation = null; + busy = executing = false; cancelRequested = false; clock.Stop(); if (disposing || IsDisposed) return; + timer.Stop(); punky.EndExport(); UpdateButtons(); if (closing) Close(); + } + private void RequestCancel() + { + if (!busy || terminalRendered || cancelRequested || cancellation == null) return; + cancelRequested = true; status.Text = stage.Text = T("正在停止匯入,等待指令回應與清理完成…", "Stopping import; waiting for command response and cleanup…"); + eta.Text = T("預估剩餘:未知(正在停止)", "Remaining: unknown (stopping)"); RenderHeartbeat(); SignalCancellation(); UpdateButtons(); + } + private void SignalCancellation() + { + if (cancellation == null || cancellationDispatch != null) return; + var owner = cancellation; + cancellationDispatch = Task.Run(() => owner.Cancel()); + } + private void RenderHeartbeat() + { + if (disposing || IsDisposed || !busy || terminalRendered) return; + MssqlImportProgress p; long advance; lock (progressGate) { p = latest; advance = lastAdvance; } + if (p != null) + { + if (executing) + { + stage.Text = cancelRequested ? T("正在停止匯入,等待清理…", "Stopping import; awaiting cleanup…") : StageText(p); + coverage.Text = T("已處理檔案範圍:", "Processed file coverage: ") + p.ProcessedBytes.ToString("N0") + " / " + p.FileBytes.ToString("N0") + " bytes · " + T("成功批次 ", "successful batches ") + p.SuccessfulBatches.ToString("N0") + T(";失敗/略過 ", "; failed/skipped ") + p.FailedBatches.ToString("N0") + "\r\n" + T("成功範圍 ", "Successful coverage ") + p.SuccessfulBytes.ToString("N0") + T(" bytes;略過範圍 ", " bytes; skipped coverage ") + p.SkippedBytes.ToString("N0") + " bytes"; + position.Text = T("目標:", "Target: ") + target.Text + "\r\n" + (p.BatchNumber > 0 ? T("目前批次 ", "Current batch ") + p.BatchNumber.ToString("N0") + T(" · 行 ", " · lines ") + p.StartLine.ToString("N0") + "–" + p.EndLine.ToString("N0") + " · byte " + p.StartByte.ToString("N0") + "–" + p.EndByte.ToString("N0") : p.Stage == MssqlImportStage.Executing ? T("正在確認執行 session,尚未確認任何批次。", "Checking execution session; no batch acknowledged yet.") : T("正在核對或收尾;請以最終結果為準。", "Verifying or finishing; await the terminal result.")); + bar.Style = ProgressBarStyle.Continuous; bar.Value = Percent(p.ProcessedBytes, p.FileBytes); + if (errors.Text != p.RecentErrorText) errors.Text = p.RecentErrorText; + logPath.Text = p.LogPath ?? logPath.Text; + errorCount.Text = (p.LogTruncated ? T("已截段;僅保留最近最多 100 筆/64 KiB UTF-16 文字。", "Truncated; recent at most 100 events / 64 KiB UTF-16 text.") : T("最近錯誤紀錄。", "Recent error events.")) + T(" 共 ", " Total ") + p.TotalErrors.ToString("N0") + T(" 筆;完整 log 路徑見上方。", " events; full log path above."); + } + else { + checkSummary.Text = T("正在串流分析:", "Streaming analysis: ") + p.ScannedBytes.ToString("N0") + " / " + fileBytes.ToString("N0") + T(" bytes;尚未執行 SQL。", " bytes; no source SQL executed."); + scanBar.Style = ProgressBarStyle.Continuous; scanBar.Value = Percent(p.ScannedBytes, fileBytes); + } + } + elapsed.Text = T("已經過:", "Elapsed: ") + Duration(clock.Elapsed); + bool stale = (Stopwatch.GetTimestamp() - advance) / (double)Stopwatch.Frequency >= 5; + bool known = executing && !cancelRequested && !stale && p != null && p.Stage == MssqlImportStage.Executing && p.Phase != MssqlImportPhase.Indexes && p.Phase != MssqlImportPhase.Constraints && p.Remaining.HasValue && p.EstimatedFinish.HasValue; + eta.Text = known ? T("預估剩餘:約 ", "Remaining: about ") + Duration(p.Remaining.Value) + T(" · 預計完成 ", " · Estimated finish ") + p.EstimatedFinish.Value.ToLocalTime().ToString("HH:mm:ss", CultureInfo.InvariantCulture) : T("預估剩餘:未知/計算中(目前指令或核對中)", "Remaining: unknown / estimating (current command or verification)"); UpdateButtons(); + } + private void RenderResult(MssqlImportResult result) + { + terminalRendered = true; stage.Text = status.Text = StatusText(result.Status); + stage.ForeColor = result.Status == MssqlImportStatus.Completed ? ThemeManager.SuccessColor : result.Status == MssqlImportStatus.CompletedWithErrors || result.Status == MssqlImportStatus.Cancelled ? ThemeManager.WarningColor : ThemeManager.DangerColor; + elapsed.Text = T("已經過:", "Elapsed: ") + Duration(result.Elapsed); eta.Text = T("預估剩餘:未知(作業已結束)", "Remaining: unknown (job ended)"); logPath.Text = result.LogPath ?? logPath.Text; + resultText.Visible = true; resultText.Text = StatusText(result.Status) + "\r\n" + T("目標:", "Target: ") + target.Text + "\r\n" + T("成功批次:", "Successful batches: ") + result.SuccessfulBatches.ToString("N0") + T(";失敗/略過:", "; failed/skipped: ") + result.FailedBatches.ToString("N0") + "\r\n" + T("已處理檔案範圍:", "Processed file coverage: ") + result.ProcessedBytes.ToString("N0") + " / " + result.FileBytes.ToString("N0") + " bytes" + "\r\n" + T("最後確認批次:", "Last acknowledged batch: ") + result.LastAcknowledgedBatch.ToString("N0") + T(";未確認批次:", "; uncertain batch: ") + (result.UncertainBatch?.ToString("N0") ?? T("無", "none")) + "\r\n" + string.Join("\r\n", (result.ValidationSummary ?? "ImportFailed").Split(';').Select(Explain)) + "\r\n" + CleanupText(result.Cleanup) + "\r\n" + PartialWarning(); + coverage.Text = T("已處理檔案範圍:", "Processed file coverage: ") + result.ProcessedBytes.ToString("N0") + " / " + result.FileBytes.ToString("N0") + " bytes"; bar.Style = ProgressBarStyle.Continuous; bar.Value = Percent(result.ProcessedBytes, result.FileBytes); + errorCount.Text = (errors.Text.Length >= 32768 || result.TotalErrors > 100 ? T("已截段;最近最多 100 筆/64 KiB UTF-16。", "Truncated; recent at most 100 events / 64 KiB UTF-16.") : T("最近錯誤紀錄。", "Recent errors.")) + T(" 共 ", " Total ") + result.TotalErrors.ToString("N0") + T(" 筆;完整 log 路徑見上方。", " events; full log path above."); Reflow(); + } + private static int Percent(long bytes, long total) => total <= 0 ? 0 : (int)Math.Max(0, Math.Min(100, 100.0 * bytes / total)); + private static string Duration(TimeSpan value) => ((long)Math.Max(0, value.TotalHours)).ToString("00") + ":" + value.Minutes.ToString("00") + ":" + value.Seconds.ToString("00"); + private static string PartialWarning() => T("已執行的結構與資料可能保留,目前批次也可能部分生效;沒有整份檔案的自動回復或續跑。請先檢查目標與 log,再決定如何重新匯入。", "Applied schema/data and partial current-batch effects may remain. No whole-file undo or resume. Review the target and log before importing again."); + private static string StatusText(MssqlImportStatus status) + { + switch (status) + { + case MssqlImportStatus.Completed: return T("匯入執行完成", "Import execution completed"); + case MssqlImportStatus.CompletedWithErrors: return T("執行完成,但有錯誤", "Execution completed with errors"); + case MssqlImportStatus.Cancelled: return T("這次匯入已取消", "Import cancelled"); + case MssqlImportStatus.CleanupUncertain: return T("清理或執行結果尚未確認", "Cleanup or execution outcome is unconfirmed"); + default: return T("匯入已停止:發生錯誤", "Import stopped: error"); + } + } + private static string StageText(MssqlImportProgress p) + { + if (p.Stage == MssqlImportStage.Stopping) return T("正在停止匯入,等待清理…", "Stopping import; awaiting cleanup…"); + if (p.Stage == MssqlImportStage.Verifying) return T("正在核對 session、檔案與必要摘要…", "Verifying session, file and applicable summary…"); + if (p.Stage == MssqlImportStage.Finished) return T("正在整理執行結果…", "Preparing terminal result…"); + return p.Phase == MssqlImportPhase.Indexes ? T("正在建立索引…", "Creating indexes…") : p.Phase == MssqlImportPhase.Constraints ? T("正在建立約束…", "Creating constraints…") : p.Phase == MssqlImportPhase.Schema ? T("正在執行結構批次…", "Executing schema batches…") : T("正在依序執行 SQL 批次…", "Executing SQL batches in order…"); + } + private static string CleanupText(MssqlImportCleanup cleanup) + { + if (cleanup == null) return T("清理狀態:尚未取得確認。", "Cleanup: no confirmed receipt."); + return T("指令已結束:", "Command ended: ") + Yes(cleanup.CommandEnded) + T(";session 已釋放:", "; session released: ") + Yes(cleanup.SessionReleased) + T(";未提交交易清理已確認:", "; transaction cleanup confirmed: ") + Yes(cleanup.TransactionCleanupConfirmed) + (string.IsNullOrWhiteSpace(cleanup.IssueCode) ? "" : "\r\n" + string.Join("\r\n", cleanup.IssueCode.Split(';').Select(Explain))); + } + private static string Yes(bool value) => value ? T("是", "yes") : T("尚未確認", "unconfirmed"); + internal static string Explain(string code) + { + switch (code) + { + case "SourceRequired": return T("請先選擇 SQL 檔案。", "Choose a SQL file."); + case "TargetRequired": return T("請先選擇目標資料庫。", "Select a target database."); + case "TargetReadOnly": return T("目標資料庫為唯讀,無法匯入。", "Target is read only."); + case "TargetIdentityUnavailable": return T("無法確認實際伺服器與資料庫識別。", "Actual server/database identity unavailable."); + case "TargetVisibilityRequired": return T("無法完整確認目標物件;結構匯出須確認空庫。", "Complete visibility is required to prove an empty schema target."); + case "TargetNotEmpty": return T("結構匯出需要空目標;請另選資料庫,精靈不會清空物件。", "Schema import requires an empty target; select another database."); + case "CreateTableRequired": return T("無法確認建立資料表的必要權限。", "Required CREATE TABLE permission unconfirmed."); + case "CreateTableNotProven": case "CreateViewNotProven": return T("建立物件權限未能完整確認,實際 SQL 仍可能失敗。", "Creation permissions not fully known; SQL may still fail."); + case "TargetNotProvenEmpty": return T("目標未確認為空;一般或資料型腳本依自身 SQL 與權限執行。", "Target not proven empty; generic/data SQL uses existing permissions."); + case "SessionIntrinsicsMayChange": return T("批次間狀態查詢可能改變 @@ROWCOUNT/@@ERROR;需保留時請在同一 batch 先自行保存。", "Interbatch probes may change @@ROWCOUNT/@@ERROR; preserve them in the same batch if needed."); + case "PartialBatchWritesMayRemain": return PartialWarning(); + case "Cancelled": case "PreviouslyCommittedWritesMayRemain": return T("已停止排程;先前已提交的寫入可能保留。", "Scheduling stopped; previously committed writes may remain."); + case "LogIncomplete": return T("完整錯誤紀錄未確認存妥。請保留畫面內容與現有 log,後續批次已停止。", "Full log persistence unconfirmed. Retain preview and existing log; later batches stopped."); + case "SqlBatchFailed": return T("SQL 批次失敗;請查看下方錯誤與完整 log。", "SQL batch failed; inspect errors and full log."); + case "AllBatchesExecuted": return T("所有批次已完成執行。", "All batches executed."); + case "NoDataContentValidation": return T("一般/資料型腳本未提供可比較的完整摘要;未核對資料內容。", "Generic/data SQL has no comparable full manifest; data contents not verified."); + case "AllBatchesProcessedWithErrors": case "FullRestoreNotValidated": return T("已遍歷檔案但含失敗/略過批次,未通過完整還原核對。", "File processed with failed/skipped batches; full restore not validated."); + case "NativeSummaryCountsMatched": return T("native 摘要的資料表數與總筆數相符。", "Native footer table and total-row counts match."); + case "NotColumnContentValidation": return T("此核對僅限表數與總筆數,不代表逐欄資料內容相同。", "Count-only validation; column contents were not compared."); + case "TargetChanged": return T("目標識別已變更,作業停止。", "Target identity changed; job stopped."); + case "DigestMismatch": return T("檔案 digest 與預掃描不符,已執行部分無法自動撤回。", "File digest differs from preflight; applied changes cannot be undone."); + case "SummaryMismatch": return T("資料表數或總筆數與 native 摘要不符。", "Counts differ from native summary."); + case "EofTransactionOpen": return T("檔尾仍有未結交易,不能視為成功。", "An open transaction remains at EOF."); + case "SessionStateInvalid": return T("無法確認 session/交易狀態,作業停止。", "Session/transaction state invalid; stopped."); + case "LobStateInvalid": case "LobInitializationMissing": return T("native LOB 傳輸狀態不完整或不一致,不能略過。", "Native LOB state missing/inconsistent; cannot skip."); + case "PreflightInvalidOrConsumed": return T("預檢已失效或已使用,請重新檢查。", "Preflight invalid/consumed; recheck."); + case "EmbeddedNul": return T("v1 不支援 SQL 文字中的 U+0000;也請確認是否為無 BOM 的 UTF-16。", "v1 does not support U+0000 in SQL text; check for BOM-less UTF-16."); + case "BatchTooLarge": return T("單一 GO 批次超過 32 MiB 解碼上限,請調整來源匯出批次後重產檔案。", "GO batch exceeds 32 MiB decoded; regenerate smaller batches."); + case "UnsupportedGo": case "UnsupportedGoSyntax": return T("GO 語法不支援:不可重複次數或在分隔行使用 block comment。", "Unsupported GO repeat count or block comment delimiter."); + case "SqlCmdUnsupported": case "SqlcmdUnsupported": case "UnsupportedSqlCmd": case "UnsupportedSqlcmd": return T("不支援 SQLCMD 指令或變數替代。", "SQLCMD directives/substitution unsupported."); + case "InvalidEncoding": case "UnsupportedEncoding": return T("檔案編碼無效或不支援;需要 UTF-8 或帶 BOM 的 UTF-16。", "Invalid encoding; use UTF-8 or BOM-marked UTF-16."); + case "DatabaseChange": case "CrossDatabaseUse": case "UnsupportedUse": return T("不支援直接 USE 切換至另一資料庫。", "Direct USE to another database unsupported."); + case "CleanupStillActive": case "SessionUnavailable": case "TransactionCleanupUnconfirmed": case "TransactionCleanupFailed": case "CleanupUnconfirmed": case "CleanupFailed": case "SessionReleaseFailed": case "CommandStillActive": case "CleanupReceiptMissing": case "ExecutionOutcomeUnknown": case "UnexpectedWorkerFailure": return T("執行或清理結果尚未確認,請依 log 核對目標。", "Execution/cleanup unconfirmed; inspect target using log."); + case "NativeFormat": return T("mySQLPunk 匯出標記或 LOB job/完成摘要不完整或不一致。", "Native export markers, LOB job or completion summary are missing/inconsistent."); + case "UnclosedContext": return T("檔案結尾有未閉合的字串、識別字或註解。", "Unclosed string, identifier or comment at EOF."); + case "PreflightFailed": return T("無法完成預檢,請確認檔案可讀、連線設定與 log 目錄可寫。", "Preflight failed; check readable file, connection and writable log directory."); + case "ImportFailed": return T("匯入因檔案、連線或執行異常停止,請核對 log 與目標。", "Import stopped on file/connection/execution error; inspect log and target."); + case "InputReleaseFailed": return T("來源檔案 handle 釋放未確認。", "Source handle release unconfirmed."); + default: return T("檢查或執行未完成,診斷代碼:", "Check/execution incomplete; diagnostic code: ") + code; + } + } + private bool HasLog() => !string.IsNullOrWhiteSpace(logPath.Text) && File.Exists(logPath.Text); + private void OpenLogPath(bool folder) + { + if (!HasLog()) return; string path = folder ? Path.GetDirectoryName(logPath.Text) : logPath.Text; + try { if (PathOpener != null) PathOpener(path); else Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }); } + catch (Exception) { status.Text = T("無法開啟路徑,請使用上方完整路徑。", "Cannot open path; use full path above."); } + } + protected override void Dispose(bool disposingManaged) + { + if (disposingManaged && !disposing) + { + lock (progressGate) { disposing = true; acceptingProgress = false; generation++; latest = null; activeJob = Guid.Empty; } + SignalCancellation(); + DiscardPrepared(); timer.Dispose(); + } + base.Dispose(disposingManaged); + } + } +} diff --git a/mySQLPunk/mySQLPunk.csproj b/mySQLPunk/mySQLPunk.csproj index b1511c8..ec62418 100644 --- a/mySQLPunk/mySQLPunk.csproj +++ b/mySQLPunk/mySQLPunk.csproj @@ -300,7 +300,9 @@ + + diff --git a/tests/Run-SmokeTests.ps1 b/tests/Run-SmokeTests.ps1 index bf3839a..d797e43 100644 --- a/tests/Run-SmokeTests.ps1 +++ b/tests/Run-SmokeTests.ps1 @@ -143,7 +143,7 @@ if (!(Test-Path -LiteralPath $mysqlConnector)) { /r:System.Core.dll ` /r:System.IO.Compression.dll ` /r:System.IO.Compression.FileSystem.dll ` - (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Parser.cs") $source $preferencesSource $schemaSyncSource $erModelSource (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Snapshot.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Schema.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.ViewReferences.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Properties.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Artifact.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Values.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Lob.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Routing.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.SnapshotIntegration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.CompatibilityIntegration.cs") + (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlImport.Parser.cs") $source $preferencesSource $schemaSyncSource $erModelSource (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Snapshot.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Schema.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.ViewReferences.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Properties.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Artifact.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Values.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Lob.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Worker.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Wizard.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Routing.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.Integration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.SnapshotIntegration.cs") (Join-Path $PSScriptRoot "SmokeTests.MssqlExport.CompatibilityIntegration.cs") if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/tests/SmokeTests.MssqlImport.Wizard.cs b/tests/SmokeTests.MssqlImport.Wizard.cs new file mode 100644 index 0000000..c3f3535 --- /dev/null +++ b/tests/SmokeTests.MssqlImport.Wizard.cs @@ -0,0 +1,645 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using mySQLPunk; +using mySQLPunk.lib.MssqlImport; + +public static partial class SmokeTests +{ + private static void ImportWizard_GatesAndInvalidation() + { + using (var fixture = new ImportWizardFixture()) + using (var form = fixture.CreateForm()) + { + form.Show(); Application.DoEvents(); + Assert(fixture.SessionCalls == 0, "Showing selected-target setup must not open DB/session."); + Assert(!IWFind(form, "importSkipErrors").Checked, "Skip failed GO batches defaults off."); + Assert(!IWFind(form, "importConfirmTarget").Checked, "Target confirmation is never assumed."); + Assert(IWFind(form, "importTarget").ReadOnly, "Existing tree target is display-only."); + IWClick(form, "importNext"); + IWPump(() => IWFind