铜陵经侦
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

259 lines
10 KiB

import java.nio.file.*;
import java.sql.*;
import java.util.*;
import java.util.stream.*;
/**
* 增量 SQL 执行器:仅执行 t_sql_migration 中尚未记录的脚本,避免重复执行。
*/
public class RunAllSql {
private static final String URL =
"jdbc:kingbase8://8.162.3.203:54321/economic_crime_dev?currentSchema=public&clientEncoding=utf8&socketTimeout=30000&loginTimeout=30";
private static final String USER = "dcms_dev";
private static final String PASS = "sdy@2025#dc$ks";
/** 迁移追踪表引入前已在库中执行过的脚本(仅首次 bootstrap 写入,不重复跑) */
private static final String[] BOOTSTRAP_APPLIED = {
"20260625_add_disposal_status.sql",
"20260626_fix_check_constraints.sql",
"20260627_add_alarm_category.sql",
"20260627_add_alarm_detail_fields.sql",
"20260627_add_evidence_file_key.sql",
"20260629_add_case_type_77_dict.sql",
"20260629_reorganize_top_menus.sql",
"20260706_alarm_source_register.sql",
"20260706_alarm_void_roles.sql",
"20260706_fix_evidence_type_check.sql",
"20260708_void_audit_menu.sql",
"20260709_void_audit_grant_jz_admin.sql",
"20260711_migrate_pending_info_to_pending_review.sql",
"20260722_alarm_audit_group.sql",
"20260731_property_transfer_menu.sql",
};
/** 显式顺序清单;自动扫描 docs/202*.sql 时会与此合并去重排序 */
private static final String[] SCRIPTS = {
"00000000_sql_migration_table.sql",
"20260625_add_disposal_status.sql",
"20260626_fix_check_constraints.sql",
"20260627_add_alarm_category.sql",
"20260627_add_alarm_detail_fields.sql",
"20260627_add_evidence_file_key.sql",
"20260629_add_case_type_77_dict.sql",
"20260629_reorganize_top_menus.sql",
"20260706_alarm_source_register.sql",
"20260706_alarm_void_roles.sql",
"20260706_fix_evidence_type_check.sql",
"20260708_void_audit_menu.sql",
"20260709_void_audit_grant_jz_admin.sql",
"20260711_migrate_pending_info_to_pending_review.sql",
"20260722_alarm_audit_group.sql",
"20260731_property_transfer_menu.sql",
"20260731_property_return_checkout_menu.sql",
"20260731_property_tables.sql",
"20260804_case_seizure_doc_table.sql",
"20260804_property_unregistered_menu.sql",
"20260804_case_property_item_table.sql",
"20260804_property_omission_menu.sql",
"20260804_property_transfer_audit_flow.sql",
"20260804_property_return_audit_flow.sql",
"20260804_property_checkout_audit_flow.sql",
"20260804_dossier_module.sql",
"20260805_tl_police_department_org.sql",
"20260805_hide_system_demo_menus.sql",
"20260805_add_alarm_case_source.sql",
"20260805_alarm_no_accept_review.sql",
"20260805_fix_employee_sequence.sql",
"20260805_fix_duplicate_employee_email.sql",
"20260805_sync_all_function_permissions.sql",
"20260805_fix_alarm_audit_permission_codes.sql",
"20260907_dossier_borrow_self_seed.sql",
};
public static void main(String[] args) throws Exception {
Class.forName("com.kingbase8.Driver");
Path base = Paths.get("d:/project/economic_crime/docs");
List<String> scriptList = resolveScripts(base);
int ran = 0;
int skipped = 0;
int fail = 0;
try (Connection conn = DriverManager.getConnection(URL, USER, PASS)) {
conn.setAutoCommit(true);
System.out.println("Connected: economic_crime_dev");
ensureMigrationTable(conn);
bootstrapIfEmpty(conn);
for (String file : scriptList) {
Path path = base.resolve(file);
if (!Files.exists(path)) {
System.out.println("[SKIP missing] " + file);
skipped++;
continue;
}
if (isApplied(conn, file)) {
System.out.println("[SKIP applied] " + file);
skipped++;
continue;
}
System.out.println("[RUN] " + file);
boolean fileOk = executeFile(conn, Files.readString(path));
if (fileOk) {
markApplied(conn, file);
System.out.println(" => OK");
ran++;
} else {
System.out.println(" => FAIL (not recorded)");
fail++;
}
}
printPropertyMenus(conn);
}
System.out.printf("%nDone: %d ran, %d skipped, %d failed%n", ran, skipped, fail);
if (fail > 0) System.exit(1);
}
private static List<String> resolveScripts(Path base) throws Exception {
Set<String> names = new LinkedHashSet<>(Arrays.asList(SCRIPTS));
try (DirectoryStream<Path> stream = Files.newDirectoryStream(base, "202*.sql")) {
for (Path p : stream) {
names.add(p.getFileName().toString());
}
}
try (DirectoryStream<Path> stream = Files.newDirectoryStream(base, "00000000_*.sql")) {
for (Path p : stream) {
names.add(p.getFileName().toString());
}
}
return names.stream().sorted().collect(Collectors.toList());
}
private static void ensureMigrationTable(Connection conn) throws SQLException {
String ddl = """
CREATE TABLE IF NOT EXISTS t_sql_migration (
script_name VARCHAR(128) PRIMARY KEY,
executed_at TIMESTAMP NOT NULL DEFAULT NOW(),
success_flag BOOLEAN NOT NULL DEFAULT TRUE
)
""";
try (Statement s = conn.createStatement()) {
s.execute(ddl);
}
}
private static void bootstrapIfEmpty(Connection conn) throws SQLException {
int count = 0;
try (Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("SELECT COUNT(*) FROM t_sql_migration")) {
if (rs.next()) count = rs.getInt(1);
}
if (count > 0) return;
System.out.println("[BOOTSTRAP] seeding historical applied scripts...");
for (String script : BOOTSTRAP_APPLIED) {
markApplied(conn, script);
System.out.println(" [seed] " + script);
}
}
private static boolean isApplied(Connection conn, String script) throws SQLException {
try (PreparedStatement ps = conn.prepareStatement(
"SELECT 1 FROM t_sql_migration WHERE script_name = ? AND success_flag = TRUE")) {
ps.setString(1, script);
try (ResultSet rs = ps.executeQuery()) {
return rs.next();
}
}
}
private static void markApplied(Connection conn, String script) throws SQLException {
try (PreparedStatement ps = conn.prepareStatement(
"INSERT INTO t_sql_migration (script_name, executed_at, success_flag) "
+ "SELECT ?, NOW(), TRUE WHERE NOT EXISTS ("
+ "SELECT 1 FROM t_sql_migration WHERE script_name = ?)")) {
ps.setString(1, script);
ps.setString(2, script);
ps.executeUpdate();
}
}
private static boolean executeFile(Connection conn, String sql) throws SQLException {
List<String> statements = splitStatements(sql);
boolean fileOk = true;
for (String stmt : statements) {
if (stmt.isBlank()) continue;
try (Statement s = conn.createStatement()) {
s.execute(stmt);
} catch (SQLException e) {
if (isIgnorable(e)) {
System.out.println(" [SKIP stmt] " + shorten(e.getMessage()));
} else {
System.out.println(" [FAIL stmt] " + shorten(e.getMessage()));
fileOk = false;
}
}
}
return fileOk;
}
private static void printPropertyMenus(Connection conn) throws SQLException {
System.out.println("\n--- 涉案财物菜单验证 ---");
try (Statement s = conn.createStatement();
ResultSet rs = s.executeQuery(
"SELECT menu_name, path, web_perms FROM t_menu WHERE deleted_flag = 0 "
+ "AND (path LIKE '/property/%' OR web_perms LIKE 'property:%') ORDER BY menu_id")) {
while (rs.next()) {
System.out.printf(" %s | %s | %s%n",
rs.getString(1), rs.getString(2), rs.getString(3));
}
}
}
private static boolean isIgnorable(SQLException e) {
String msg = e.getMessage().toLowerCase(Locale.ROOT);
return msg.contains("already exists")
|| msg.contains("duplicate key")
|| (msg.contains("does not exist") && msg.contains("drop"));
}
private static String shorten(String msg) {
if (msg == null) return "";
int idx = msg.indexOf('\n');
return idx > 0 ? msg.substring(0, idx) : msg;
}
static List<String> splitStatements(String sql) {
List<String> out = new ArrayList<>();
StringBuilder cur = new StringBuilder();
boolean inDollar = false;
String[] lines = sql.split("\n", -1);
for (String line : lines) {
String trimmed = line.trim();
if (!inDollar && (trimmed.startsWith("--") || trimmed.isEmpty())) {
continue;
}
if (trimmed.contains("DO $$") || trimmed.startsWith("DO $$")) {
inDollar = true;
}
cur.append(line).append('\n');
if (inDollar) {
if (trimmed.endsWith("$$;") || trimmed.equals("$$;")) {
inDollar = false;
out.add(cur.toString().trim());
cur.setLength(0);
}
} else if (trimmed.endsWith(";")) {
out.add(cur.toString().trim());
cur.setLength(0);
}
}
if (!cur.toString().trim().isEmpty()) {
out.add(cur.toString().trim());
}
return out;
}
}