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.
260 lines
10 KiB
260 lines
10 KiB
|
1 month ago
|
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;
|
||
|
|
}
|
||
|
|
}
|