Files
workspace/code/fms/.tmp-fkcheck/MigrateGen.java
T
2026-08-21 23:06:56 +08:00

94 lines
6.3 KiB
Java

import java.io.FileInputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.*;
public class MigrateGen {
record Idx(String tbl, String name, String cols, boolean isPk, boolean isUnique) {}
record Chk(String tbl, String name, String definition) {}
public static void main(String[] args) throws Exception {
Properties props = new Properties();
try (FileInputStream in = new FileInputStream(args[0])) { props.load(in); }
List<String> tables = new ArrayList<>(List.of(
"s_autocode","s_field","s_field_edit","s_field_group","s_field_query","s_field_view",
"s_i18n","s_log_audit","s_log_audit_field","s_log_login","s_log_technical",
"s_menu","s_module","s_power","s_relation","s_role","s_role_power","s_role_scope","s_user_role"));
try (Connection conn = DriverManager.getConnection(props.getProperty("url"), props.getProperty("username"), props.getProperty("password"))) {
// 1. indexes + key columns
Map<String, List<Idx>> idxByTbl = new HashMap<>();
String idxSql =
"SELECT OBJECT_NAME(i.object_id) AS tbl, i.name AS idx, i.is_unique, i.is_primary_key, " +
" STUFF((SELECT ',' + c.name FROM sys.index_columns ic " +
" JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id " +
" WHERE ic.object_id = i.object_id AND ic.index_id = i.index_id " +
" ORDER BY ic.key_ordinal FOR XML PATH('')), 1, 1, '') AS cols " +
"FROM sys.indexes i WHERE i.object_id IN (SELECT object_id FROM sys.tables WHERE name LIKE 's' + char(95) + '%') AND i.type IN (1,2) AND i.is_disabled = 0";
try (Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(idxSql)) {
while (rs.next()) {
String tbl = rs.getString("tbl");
idxByTbl.computeIfAbsent(tbl, k -> new ArrayList<>()).add(
new Idx(tbl, rs.getString("idx"), rs.getString("cols"),
rs.getBoolean("is_primary_key"), rs.getBoolean("is_unique")));
}
}
// 2. check constraints
Map<String, List<Chk>> chkByTbl = new HashMap<>();
String chkSql = "SELECT OBJECT_NAME(parent_object_id) AS tbl, name, definition FROM sys.check_constraints WHERE parent_object_id IN (SELECT object_id FROM sys.tables)";
try (Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(chkSql)) {
while (rs.next()) {
String tbl = rs.getString("tbl");
chkByTbl.computeIfAbsent(tbl, k -> new ArrayList<>()).add(
new Chk(tbl, rs.getString("name"), rs.getString("definition")));
}
}
// 3. generate script
String out = "migrate_identity_to_snowflake.sql";
try (PrintWriter w = new PrintWriter(out, StandardCharsets.UTF_8)) {
w.println("-- Migrate s_* tables: b_id identity(1,1) -> plain bigint (snowflake by app layer)");
w.println("-- Generated: " + new Timestamp(System.currentTimeMillis()));
for (String tbl : tables) {
List<Idx> idxs = idxByTbl.getOrDefault(tbl, List.of());
List<Chk> chks = chkByTbl.getOrDefault(tbl, List.of());
List<Idx> pk = idxs.stream().filter(i -> i.isPk()).toList();
List<Idx> bIdIdx = idxs.stream().filter(i -> !i.isPk() && i.cols().contains("b_id")).toList();
List<Chk> bIdChk = chks.stream().filter(c -> c.definition().contains("b_id")).toList();
List<Idx> bIdUq = bIdIdx.stream().filter(i -> i.isUnique()).toList();
List<Idx> bIdNc = bIdIdx.stream().filter(i -> !i.isUnique()).toList();
w.println();
w.println("-- ===== " + tbl + " =====");
if (pk.isEmpty()) { w.println("-- [SKIP] no PK found"); continue; }
w.println("ALTER TABLE [dbo].[" + tbl + "] DROP CONSTRAINT [" + pk.get(0).name() + "];");
for (Chk c : bIdChk) w.println("ALTER TABLE [dbo].[" + tbl + "] DROP CONSTRAINT [" + c.name() + "];");
for (Idx i : bIdUq) w.println("ALTER TABLE [dbo].[" + tbl + "] DROP CONSTRAINT [" + i.name() + "];");
for (Idx i : bIdNc) w.println("DROP INDEX [" + i.name() + "] ON [dbo].[" + tbl + "];");
w.println("ALTER TABLE [dbo].[" + tbl + "] ADD [b_id_new] bigint NULL;");
w.println("UPDATE [dbo].[" + tbl + "] SET [b_id_new] = [b_id];");
w.println("ALTER TABLE [dbo].[" + tbl + "] ALTER COLUMN [b_id_new] bigint NOT NULL;");
w.println("ALTER TABLE [dbo].[" + tbl + "] DROP COLUMN [b_id];");
w.println("GO");
w.println("EXEC sp_rename 'dbo." + tbl + ".b_id_new', 'b_id', 'COLUMN';");
w.println("GO");
w.println("ALTER TABLE [dbo].[" + tbl + "] ADD CONSTRAINT [" + pk.get(0).name() + "] PRIMARY KEY ([b_id]);");
for (Chk c : bIdChk) w.println("ALTER TABLE [dbo].[" + tbl + "] ADD CONSTRAINT [" + c.name() + "] CHECK " + c.definition() + ";");
for (Idx i : bIdUq) w.println("ALTER TABLE [dbo].[" + tbl + "] ADD CONSTRAINT [" + i.name() + "] UNIQUE (" + i.cols() + ");");
for (Idx i : bIdNc) w.println("CREATE INDEX [" + i.name() + "] ON [dbo].[" + tbl + "] (" + i.cols() + ");");
w.println("GO");
}
w.println("-- End of migration");
}
System.out.println("Script written: " + out);
// print preview: first 60 lines
try (java.io.BufferedReader r = new java.io.BufferedReader(new java.io.InputStreamReader(
new FileInputStream(out), StandardCharsets.UTF_8))) {
String line; int n = 0;
while ((line = r.readLine()) != null && n < 60) { System.out.println(line); n++; }
System.out.println("... (" + n + " lines shown of total)");
}
}
}
}