# db **Repository Path**: tanxii/db ## Basic Information - **Project Name**: db - **Description**: idea 插件 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-05 - **Last Updated**: 2026-08-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Tanxii DB IntelliJ Plugin 这是一个基于 **IntelliJ Platform**、**Gradle** 和 **Java 21** 的 IntelliJ 插件项目。 插件当前的核心目标是: - 在 **git commit** 前识别提交中的 `.sql` 文件 - 通过项目级 `project-relative glob -> DialectProfile -> databaseTargetId` 显式锁定 MySQL、Oracle、DM、PostgreSQL 和 TDSQL PG 方言/兼容模式 - 使用统一 lexer/script frontend 执行结构、模板 IR、内层 SQL、diff 完整单元和方言规则 `precheck` - 在存在匹配数据库配置时补充 JDBC 校验 - 以 `VALID / INVALID / UNVERIFIED` 三态结论、结构化 issue 和 definitive coverage 聚合决策;严格提交模式阻断 `INVALID` 和 `UNVERIFIED` - 校验通过后可选按文件顺序自动执行 SQL;客户端指令由插件内嵌解释器处理后通过 JDBC 执行 同时,项目还提供了一个设置页,用于配置: - 编辑器 Mapper 校验和 SQL 翻译使用的大模型参数 - 数据库 `type / compatibility`、连接参数及 `Test Connect` - 当前项目下的 SQL 相对路径;项目根、目标 ID 与方言 Profile 由插件自动管理 - 提交校验通过后是否自动执行 SQL - 已存在文件是否仅校验 diff 涉及的完整 SQL 语句 --- ## 技术栈 - Java 21 - Gradle Wrapper - IntelliJ Platform Plugin - Swing / IntelliJ UI Components - JUnit 5 - Jackson - JDBC Drivers --- ## 目录结构 当前项目的主要结构如下: ```text . ├── .run/ ├── gradle/ │ ├── libs.versions.toml │ └── wrapper/ ├── src/ │ ├── main/ │ │ ├── java/com/tanxii/ │ │ │ ├── commit/ │ │ │ │ ├── SqlCommitCheckHandler.java │ │ │ │ ├── SqlCommitCheckinHandlerFactory.java │ │ │ │ ├── SqlCommitFileReader.java │ │ │ │ ├── SqlCommitFileValidator.java │ │ │ │ ├── SqlCommitValidationOutcome.java │ │ │ │ └── decision/ │ │ │ ├── i18n/ │ │ │ │ └── MyMessageBundle.java │ │ │ ├── settings/ │ │ │ │ ├── PluginSettings.java │ │ │ │ ├── PluginSettingsConfigurable.java │ │ │ │ ├── PluginSettingsState.java │ │ │ │ └── database/ │ │ │ │ ├── DatabaseConfig.java │ │ │ │ ├── DatabaseConfigItemPanel.java │ │ │ │ ├── DatabaseConfigState.java │ │ │ │ ├── DatabaseConnectionTestRequest.java │ │ │ │ ├── DatabaseConnectionTestResult.java │ │ │ │ ├── DatabaseConnectionTestService.java │ │ │ │ ├── DatabaseDriverAdapter.java │ │ │ │ └── adapter/ │ │ │ ├── sql/ │ │ │ │ ├── dialect/ │ │ │ │ ├── precheck/ │ │ │ │ │ ├── SqlPrecheckService.java │ │ │ │ │ ├── model/ │ │ │ │ │ ├── parser/ │ │ │ │ │ └── rule/ │ │ │ │ └── validation/ │ │ │ │ ├── agent/ │ │ │ │ └── model/ │ │ │ └── toolwindow/ │ │ │ └── MyToolWindowFactory.java │ │ └── resources/ │ │ ├── META-INF/plugin.xml │ │ └── messages/MyMessageBundle.properties │ └── test/ │ └── java/com/tanxii/ │ ├── commit/ │ ├── i18n/ │ ├── settings/ │ ├── sql/ │ └── toolwindow/ ├── build.gradle ├── gradle.properties ├── gradlew ├── gradlew.bat └── README.md ``` --- ## 包职责说明 ### `com.tanxii.commit` 负责提交拦截主链路: - 收集本次提交中的文件 - 过滤 `.sql` 文件 - 组织后台预检查、可选自动执行和提交重试 - 决定是否允许提交继续 ### `com.tanxii.commit.decision` 负责提交结果聚合与决策模型: - 单文件校验结果 - 提交级决策对象 - 决策汇总服务 ### `com.tanxii.i18n` 负责国际化消息访问层: - `MyMessageBundle` ### `com.tanxii.settings` 负责插件设置页与持久化配置: - `PluginSettings` - `PluginSettingsState` - `PluginSettingsConfigurable` ### `com.tanxii.settings.database` 负责数据库配置和连接测试: - 数据库配置模型 - 设置页数据库卡片 UI - 连接测试服务与请求/结果模型 ### `com.tanxii.settings.database.adapter` 负责不同数据库的 JDBC 适配: - MySQL - Oracle - DM 原生 / Oracle 兼容 - PostgreSQL - TDSQL PostgreSQL 原生 / Oracle 兼容 ### `com.tanxii.sql.dialect` 负责根据路径识别 SQL 方言。 ### `com.tanxii.sql.precheck` 负责本地预检查编排。 #### `com.tanxii.sql.precheck.model` 负责 precheck 阶段的数据结构: - issue - result - statement info - analysis result #### `com.tanxii.sql.precheck.parser` 负责 SQL 文本解析: - 切句 - 结构问题识别 - statement type 识别 - block/delimiter 处理 #### `com.tanxii.sql.precheck.rule` 负责方言规则检查: - MySQL - Oracle - DM - PostgreSQL ### `com.tanxii.sql.validation.agent` 当前为远程 LLM 提交校验预留包,尚未接入 git commit 链路。 ### `com.tanxii.sql.validation.model` 负责远程校验请求/结果模型。 ### `com.tanxii.toolwindow` 负责插件 Tool Window 的 UI 入口。 --- ## 构建与测试 ### 构建插件 ```bash ./gradlew build ``` ### 运行全部测试 ```bash ./gradlew test ``` 默认测试排除耗时的仓库 SQL 全量审计。运行全部 SQL 语料的方言预检查: ```bash ./gradlew repositorySqlAudit ``` 该任务用于发现语料中的真实方言问题,并按 profile/statement family 输出 invalid、unverified rate 和 definitive coverage。版本化正反例语料门禁: ```bash ./gradlew sqlAccuracyTest ``` ### 运行单个测试类 ```bash ./gradlew test --tests com.tanxii.settings.PluginSettingsConfigurableTest ``` ### 运行单个测试方法 ```bash ./gradlew test --tests com.tanxii.settings.PluginSettingsConfigurableTest.testConnectUsesCurrentTypeCompatibilityAndCredentials ``` ### 启动带插件的 IDE ```bash ./gradlew runIde ``` ### 校验插件兼容性 ```bash ./gradlew verifyPlugin ``` ### 清理构建产物 ```bash ./gradlew clean ``` --- ## 插件入口 插件入口配置位于: - `src/main/resources/META-INF/plugin.xml` 当前关键入口包括: - Tool Window:`com.tanxii.toolwindow.MyToolWindowFactory` - Settings:`com.tanxii.settings.PluginSettingsConfigurable` - Commit Hook:`com.tanxii.commit.SqlCommitCheckinHandlerFactory` --- ## 设置页说明 设置页支持以下配置: ### 1. LLM 配置 默认仅显示通用必要项: - Provider(Custom / OpenAI / DeepSeek / 通义千问 / Ollama / Azure OpenAI) - Base URL 或完整的 `/chat/completions` 地址 - API Key(本地无鉴权模型服务可留空) - Model(可通过 `/models` 接口加载) 勾选“显示高级配置”后展开以下明细,并记住展开状态: - Context Tokens / Max Output Tokens(供应商预设会给出默认值,可手工覆盖) - Input / Output Price(可选,USD / 1M Tokens;仅基于服务端 usage 在本地估算) - API Key Header / Header Value Prefix(支持 Bearer、Azure `api-key` 和企业自定义网关) - 发送前本地敏感内容扫描(默认开启,本地回环模型同样适用) - SQL 翻译只读 Schema 上下文(默认关闭,连接失败时安全降级) - 清空仅驻留当前 IDE 进程的大模型会话缓存 - Mapper 校验 / SQL 翻译功能 Profile(可分别覆盖 Model、Max Output Tokens、Temperature 和结构化输出能力;默认继承公共配置) - 已授权远程模型域名列表(显示首次确认时间,可逐项撤销;不支持通配符授权) 这组配置供编辑器右键菜单中的 Mapper 校验和 SQL 翻译使用,不参与提交前 SQL 校验。 模型请求遵循 IDE 代理设置,对限流、临时网关错误和明确的连接建立失败最多执行一次安全重试;支持秒数与 HTTP-date 格式的 `Retry-After`,POST 重试会复用同一 `Idempotency-Key`,取消等待后不会继续发送。首次向新的远程域名发送代码时会展示隐私确认。敏感内容扫描完全在本地执行,命中后可取消、等长脱敏后发送或仍然发送;命中原文不会写入日志或持久化文件。 编辑器功能默认继续使用 OpenAI-compatible Chat Completions;响应解析同时兼容字符串或文本块数组形式的 `content`,并按标准 SSE 事件聚合多行 `data`。reasoning/thinking 块不会作为最终 SQL,服务层另提供显式 opt-in 的 Responses API 普通与流式入口,不会自动改变现有端点行为。 真实供应商契约测试不会进入默认 `test`,只发送固定的无敏感文本,并分别覆盖连接、普通响应、流式响应和模型发现。显式配置环境变量后可按需运行: ```powershell $env:OPENAI_CONTRACT_API_KEY = "..." # 也可使用 OPENAI_API_KEY .\gradlew.bat openAiContractTest $env:DEEPSEEK_CONTRACT_API_KEY = "..." # 也可使用 DEEPSEEK_API_KEY .\gradlew.bat deepSeekContractTest $env:QWEN_CONTRACT_API_KEY = "..." # 也可使用 DASHSCOPE_API_KEY .\gradlew.bat qwenContractTest $env:OLLAMA_CONTRACT_API_URL = "http://localhost:11434/v1" $env:OLLAMA_CONTRACT_MODEL = "qwen2.5-coder" .\gradlew.bat ollamaContractTest ``` 每个供应商还可通过 `_CONTRACT_API_URL` 和 `_CONTRACT_MODEL` 覆盖默认端点与模型;`providerContractTest` 会聚合执行四项任务,因此仅适合全部环境均已配置时使用。 默认 `test` 不执行根目录 `sqls/` 的完整仓库语料审计;需要对完整 SQL 语料库执行方言预检查时,使用 `./gradlew repositorySqlAudit`。该任务会把 `sqls/` 声明为输入目录,目录缺失时明确失败。 每个远程模型域名分别记录授权及首次确认时间,API URL 切换到未授权域名时会重新确认;设置页撤销授权后,下一次请求也会再次确认。`localhost`、`127.0.0.0/8` 和 IPv6 回环地址统一视为本机端点,不需要远程域名授权。 Mapper 校验和 SQL 翻译结果提供可展开的请求详情,展示实际功能 Profile、端点域名、供应商、请求/实际模型、耗时、服务端 usage、结束原因、HTTP 尝试次数、Request ID 和可选本地成本估算。Request ID 与安全诊断可单击复制;诊断不包含 API Key、提示词或完整 SQL,服务端未返回 usage 时明确显示“未知”且不使用本地粗略 Token 估算代替。 相同的 Mapper 校验或 SQL 翻译请求会命中最多 40 条的进程内 LRU 会话缓存,结果和请求详情会明确标注缓存来源。缓存键仅保存端点、模型、提示词、功能参数和输入内容的 SHA-256 摘要,不包含 API Key,也不会写入磁盘;结果弹窗可强制重新生成,设置页可手工清空缓存,关闭 IDE 后缓存自然清除。 SQL 翻译支持: - SSE 流式显示,不支持流式的端点自动回退为普通请求 - 流式界面更新会自动合并,避免高频 Token 更新阻塞 IDE - 超长脚本按原文边界无损分块,保留 MySQL `delimiter`、Oracle/DM `/` 和 PostgreSQL dollar quote;单条超限时拒绝截断 - 分块结果合并前校验块数量、顺序和语句数,缺失、重复或乱序时禁止替换 - 目标方言本地预检查;失败后最多自动修复一次,并保留首次结果 - 比较翻译前后的语句数、表、目标列、WHERE、排序、分页和事务边界;存在语义风险时禁止直接替换,但仍可复制或 Diff 审核 - 可选通过只读 JDBC 元数据附加源表列类型、可空性和主键上下文 - 基于 Myers 算法的可扩展行级 Diff,千行 SQL 仍可逐块接受模型修改 - 弹窗内多轮“继续修改”和版本回退;历史仅保存在内存,并受轮数与总 Token 预算限制 - 未识别源方言时手工选择,并可填写一次性附加要求 - 展示请求耗时和服务端返回的 Token 使用量 - 复制结果或通过可撤销命令替换编辑器选区 Mapper 校验会限制超长输入,并按供应商能力使用严格 JSON Schema、JSON Object 或纯提示词;服务端以 400/422 拒绝能力时最多降级一次,结果弹窗显示实际模式和降级原因。本地解析会规范化未知枚举、缺失字段和错误类型。请求会发送带绝对行号的选区,同时附带直接引用的 `sql/resultMap` 上下文。双击问题可定位到报告行号。无选区时,SQL 和 Mapper 操作会尝试识别光标所在语句或节点。 ### 2. 数据库配置 - 数据库类型 - compatibility - connection(`host:port/database`) - username - password - SQL 相对路径(支持用逗号分隔多个 glob) - Test Connect 当数据库类型需要兼容模式时,会显示 compatibility 选择项;MySQL 会额外显示可选的 SQL Mode。插件自动使用当前 IntelliJ 项目作为项目根,并根据数据库类型、兼容模式和 SQL Mode 锁定方言 Profile、维护稳定数据库目标 ID。用户不再需要填写项目目录、Profile ID 或目标 ID。不同项目的数据库配置会分别展示和保存。 同一项目内数据库配置按“类型 + 有效兼容模式”保持唯一:MySQL、Oracle、PostgreSQL 各只能配置一次;DM 和 TDSQL PostgreSQL 的 native、oracle 模式可各配置一次,但相同模式不能重复。新增卡片会自动选择尚未使用的组合,全部组合配置完成后禁用新增按钮。 例如,在一张 MySQL 数据库卡片中填写: ```text SQL 路径:db/mysql/**, migrations/mysql/** ``` 旧版手写映射会自动回填到对应数据库卡片。无匹配或多路径命中仍会显式返回未解析/歧义,不会根据全局配置数量猜测。连接后的 JDBC metadata 只核对已锁定 Profile,不会静默改变语法身份。 ### 3. 提交自动执行 启用后,仅在提交 SQL 全部获得确定性结论、`UNVERIFIED = 0`、definitive coverage 100% 且文件内容未变化时执行。插件不会启动或依赖 `sqlplus`、`mysql`、`psql`、`disql` 等外部程序;客户端指令由插件进程内的解释器处理,生成的 SQL 继续使用已配置的 JDBC 驱动和批次事务执行。`PROMPT`、`SET SERVEROUTPUT`、`\echo` 等显示指令会被安全忽略,`SOURCE`、`START`、`@file`、`\i`、`\ir` 会在项目目录内递归展开。切换连接、访问操作系统、交互输入、提前退出或覆盖事务策略等无法安全模拟的指令会在建立数据库连接前阻断。前序 DDL 仍可能无法回滚,失败提示会要求人工核对数据库状态。 当前仍是显式开启的 pre-commit 模式:Git 提交与数据库事务不具备 exactly-once 原子性,产品只承诺 at-least-once 风险可见。失败后应先核对账本和数据库状态,再决定是否人工重试;非幂等 DDL 不应使用无保护自动执行。 ### 4. diff 完整语句校验 “仅校验 diff 涉及的完整 SQL 语句”默认关闭: - 关闭时,新增和修改的 SQL 文件都校验全文。 - 开启时,新增 SQL 文件仍校验全文;已存在文件根据提交前后 diff 选择受影响的完整 SQL 语句或存储过程块。 - 即使只修改一个字符,也会校验该字符所在的完整 SQL 语句,不会只校验单独的变更行。 - 无法读取提交修订、无法计算 diff 或无法可靠定位语句边界时,自动回退到全文校验。 模型 API Key 和数据库密码存放在 IntelliJ `PasswordSafe` 中。旧版本 XML 中的明文凭据会自动迁移并清除。 --- ## SQL 校验链路说明 当前 SQL 校验链路大致如下: 1. 提交阶段识别 `.sql` 文件 2. 使用项目相对 glob 解析唯一 `DialectProfile + databaseTargetId` 3. 冻结提交面板所选 `Change` 的修改前后权威 revision;缺失或不可读时 fail closed 4. 根据设置校验全文,或从 diff 中选择受影响的完整 SQL 语句块 5. 执行统一 token/source span、模板 IR 与有界分支、方言规则和语句族能力检查 6. 存在唯一匹配连接时尝试 JDBC 校验;仅明确语法 SQLState/vendor code 形成语法 ERROR,schema/权限/连接问题保持非确定性 7. 校验全部文件后交由唯一 `DecisionService` 聚合 warning、`UNVERIFIED` 和 coverage 8. 可选执行校验通过的脚本,并在执行前校验 SHA-256 内容摘要 9. 后台流程成功后自动重试提交 --- ## 测试策略 项目当前主要采用: - 轻量级单元测试 - 不启动完整 IDE 的组件树测试 - 通过 focused tests + `./gradlew test` 验证常规改动 - 通过 `./gradlew repositorySqlAudit` 独立审计仓库 SQL 语料 这也是本项目后续推荐的默认测试方式。 --- ## 说明 - 当前项目实际源码目录是 `src/main/java`,不是模板默认的 Kotlin 目录 - README 已按当前项目真实结构维护,不再以 IntelliJ 模板默认结构为准 - 真实提交校验只使用 IntelliJ 提交面板选中 `Change` 的权威 revision;修订缺失或不可读时 fail closed,不回退工作区正文。