Skip to main content

sql-extract

SQL抽取技能:从C++/Java/XML源代码中抽取内嵌SQL语句,优先使用ast-grep-mcp(AST精准匹配+constraints正则约束),CLI管道为兜底方案,识别SQL拼接点,输出文件清单

Jump to install

Source facts

Repository
hellyguo/self-ai-spec
Last source activity
July 27, 2026 at 05:57
Detected SKILL.md language
Chinese
Stars
8
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
5 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
sql-extract
description
SQL抽取技能:从C++/Java/XML源代码中抽取内嵌SQL语句,优先使用ast-grep-mcp(AST精准匹配+constraints正则约束),CLI管道为兜底方案,识别SQL拼接点,输出文件清单
# SQL 抽取技能 从源代码中**精准抽取**内嵌 SQL 语句,识别 SQL 拼接点,输出位置清单与统计。 适用场景: - 代码审查前的 SQL 注入风险点盘点 - 慢 SQL 优化的候选 SQL 收集 - 数据库迁移时的全量 SQL 走查 - 重构时的 SQL 集中化(迁移到 DAO/Mapper 层) ## 核心思路 **三层方案,优先使用 MCP**: 1. **首选层(ast-grep-mcp)**:通过 `find_code_by_rule` 使用 YAML rule 的 `pattern` + `constraints.regex` 一步完成 AST 匹配 + SQL 关键字过滤 - 优势:无需 jq 管道、无需临时文件、无需 shell 转义、直接输出结构化结果 - 适用:AI Agent 交互式分析场景(opencode/cursor 等) 2. **CLI 层(ast-grep + jq 管道)**:`ast-grep --kind string_literal --json=stream` → `jq` 正则过滤 - 优势:流式处理、适合大规模项目(万级文件)、可脚本化批量运行 - 适用:终端批量分析、CI/CD 集成、超大型项目 3. **兜底层(ripgrep)**:`rg` 直接扫描文本 - 优势:支持 XML(ast-grep 不支持 XML 语言) - 适用:MyBatis mapper.xml、配置文件 ## 工具依赖 ### MCP 模式(首选) | 工具 | 来源 | 用途 | |------|------|------| | ast-grep-mcp | MCP Server | `find_code_by_rule` / `find_code` / `test_match_code_rule` / `dump_syntax_tree` | 无需本地安装 jq,MCP 内置 AST 匹配 + regex constraints。 ### CLI 模式(兜底) | 工具 | 版本 | 安装 | 用途 | |------|------|------|------| | ast-grep | >= 0.45 | `cargo install ast-grep` | AST 提取字符串字面量 | | jq | >= 1.6 | 系统包管理器 | JSON 流过滤 | | ripgrep | >= 13 | `cargo install ripgrep` | 兜底正则检索 | | fd | >= 8 | `cargo install fd-find` | 文件枚举(可选) | 验证: ```bash ast-grep --version && jq --version && rg --version | head -1 ``` ## 执行流程 ### 步骤 1:确定目标范围 先识别项目结构,明确: - 源代码根目录(如 `QES3/src`、`qes3_client/qes-biz`) - 构建产物目录(`build/`、`target/`、`out/`)→ **必须排除** - 测试目录(`gtest/`、`src/test/`)→ 按需排除 - 第三方/二方库(`third_party/`、`lib/`)→ 按需排除 ```bash # 列出顶层目录 eza <project_root> # 统计文件数 fd --no-ignore -e cpp -e h -e hpp -t f <project_root> | wc -l # C++ fd --no-ignore -e java -t f <project_root> | wc -l # Java fd --no-ignore -e xml -t f <project_root> | wc -l # XML ``` ### 步骤 2:验证规则(MCP 模式必做) 用 `test_match_code_rule` 验证 YAML rule 在目标语言上能正确匹配 SQL 字面量、排除非 SQL 字面量: **验证 SQL 字面量能命中**: ``` test_match_code_rule( code: 'String sql = "SELECT * FROM user WHERE id = 1";', yaml: ''' id: sql-string-java language: java rule: pattern: '"$SQL"' constraints: SQL: regex: '(?i)\\b(select|insert|update|delete)\\b.*\\b(from|into|set)\\b' ''' ) ``` **验证非 SQL 字面量不命中**: ``` test_match_code_rule( code: 'String normal = "hello world";', yaml: '''<同上 rule>''' ) → 应返回 "No matches found" ``` ### 步骤 3:抽取内嵌 SQL(MCP 模式 - 首选) #### 3a. Java 内嵌 SQL ``` find_code_by_rule( project_folder: "<project_root>", yaml: ''' id: sql-string-java language: java rule: pattern: '"$SQL"' constraints: SQL: regex: '(?i)\\b(select|insert|update|delete)\\b.*\\b(from|into|set)\\b' ''' ) ``` #### 3b. C++ 内嵌 SQL ``` find_code_by_rule( project_folder: "<project_root>", yaml: ''' id: sql-string-cpp language: cpp rule: pattern: '"$SQL"' constraints: SQL: regex: '(?i)\\b(select|insert|update|delete)\\b.*\\b(from|into|set)\\b' ''' ) ``` #### 3c. 其他语言 各语言 pattern 相同(`'"$SQL"'`),只需改 `language` 字段: | 语言 | language 值 | |------|------------| | C/C++ | `cpp` | | Java | `java` | | C# | `csharp` | | Go | `go` | | Python | `python` | | Kotlin | `kotlin` | | Rust | `rust` | | Scala | `scala` | > **注意**:Go 的 raw string literal(`` `SELECT * FROM t` ``)不会被 `'"$SQL"'` 匹配, > 需额外用 pattern `` `$$$SQL` `` 匹配。参见 `templates/recipes.md`。 #### 3d. SQL 拼接点识别 Java 字符串拼接(`"SELECT * FROM " + table`)需用 `any` 组合规则: ``` find_code_by_rule( project_folder: "<project_root>", yaml: ''' id: sql-concat-java language: java rule: any: - pattern: '"$SQL"' - pattern: '"$L" + $R' constraints: SQL: regex: '(?i)\\b(select|insert|update|delete)\\b' L: regex: '(?i)\\b(select|insert|update|delete)\\b' ''' ) ``` C++ stringstream 拼接: ``` find_code_by_rule( project_folder: "<project_root>", yaml: ''' id: sql-stream-cpp language: cpp rule: pattern: '$STREAM << "$SQL"' constraints: SQL: regex: '(?i)\\b(select|insert|update|delete)\\b' ''' ) ``` ### 步骤 4:抽取内嵌 SQL(CLI 模式 - 兜底) 当 MCP 不可用、或项目文件量过大(>10k 文件)导致 MCP 超时时,回退到 CLI 管道。 #### 4a. 编写过滤脚本 ```bash cp templates/jq-filter.jq /tmp/sql-filter.jq ``` 模板详情见 `templates/jq-filter.jq`。**禁止在命令行内联复杂正则**。 #### 4b. 抽取 C++ 内嵌 SQL ```bash ast-grep run -l cpp --kind string_literal --json=stream \ --no-ignore vcs \ --globs '!**/build/**' --globs '!**/target/**' \ --globs '!**/.git/**' --globs '!**/gtest/**' \ <cpp_dirs...> \ 2>/tmp/sql_cpp.ast.err \ | jq -r -f /tmp/sql-filter.jq \ > /tmp/sql_cpp.lst 2>/tmp/sql_cpp.err ``` #### 4c. 抽取 Java 内嵌 SQL ```bash ast-grep run -l java --kind string_literal --json=stream \ --no-ignore vcs \ --globs '!**/target/**' --globs '!**/build/**' \ --globs '!**/.git/**' --globs '!**/test/**' \ <java_dirs...> \ 2>/tmp/sql_java.ast.err \ | jq -r -f /tmp/sql-filter.jq \ > /tmp/sql_java.lst 2>/tmp/sql_java.err ``` ### 步骤 5:抽取 XML 内嵌 SQL ast-grep(无论 MCP 还是 CLI)**不支持** XML 语言,必须用 ripgrep: ```bash # MyBatis mapper 风格 rg --no-ignore-vcs -n -g '*.xml' -- '(<select\b|<insert\b|<update\b|<delete\b|<sql\b)' <xml_dirs...> \ >> /tmp/sql_java.lst # 文本内嵌 SQL(非 MyBatis) rg --no-ignore-vcs -n -i -g '*.xml' \ -- '\b(select|insert\s+into|update\s+\w+\s+set|delete\s+from)\b\s+.*\b(from|where|values)\b' \ <xml_dirs...> \ >> /tmp/sql_java.lst ``` **注意**:`pom.xml` 等配置 XML 的 `<update.class>` 等自定义标签会误命中,需人工复核或加 `--glob '!pom.xml'`。 ### 步骤 6:验证与统计 **MCP 模式**:`find_code_by_rule` 返回 JSON 时,直接统计命中数、文件分布。 **CLI 模式**: ```bash # 行数 wc -l /tmp/sql_cpp.lst /tmp/sql_java.lst # 唯一文件数 cut -d: -f1 /tmp/sql_cpp.lst | sort -u | wc -l # 文件命中分布 Top 20(定位热点) cut -d: -f1 /tmp/sql_cpp.lst | sort | uniq -c | sort -rn | head -20 # 目录命中分布 cut -d: -f1 /tmp/sql_cpp.lst | sed 's|/[^/]*$||' | sort | uniq -c | sort -rn | head -10 ``` ### 步骤 7:复核(必做) **MCP 模式**:用 `find_code` 抽查单个文件的全量字符串字面量,与 SQL 命中结果对照: ``` find_code(pattern: '"$X"', language: java, project_folder: "<file_dir>") ``` **CLI 模式**: ```bash head -10 /tmp/sql_cpp.lst # 命中样本 ast-grep run -l cpp --kind string_literal <file> # 全量字面量对照 ``` ## MCP YAML Rule 详解 ### 核心 Rule 结构 ```yaml id: <rule_id> # 必填,规则唯一标识 language: <lang> # 必填,目标语言 rule: # 必填,匹配规则 pattern: '"$SQL"' # 匹配字符串字面量,$SQL 捕获内容 constraints: # 可选,对 meta-variable 施加正则约束 SQL: regex: '<pattern>' # Java 风格正则(非 PCRE) ``` ### constraints.regex 说明 - 语法:Java 正则(`java.util.regex.Pattern`),**不是** PCRE/JavaScript 正则 - `(?i)` 内联忽略大小写:有效 - `\b` 词边界:有效 - `\s` 空白:有效 - **不支持** lookbehind `(?<=...)`、named groups `(?<name>...)` 等高级特性 - 转义:YAML 中 `\b` 需写为 `\\b`,`\s` 需写为 `\\s` ### SQL 过滤正则(推荐值) **严格模式**(高精度,推荐默认使用): ``` (?i)\\b(select|insert|update|delete)\\b.*\\b(from|into|set)\\b ``` 要求动词后必须跟介词,避免 "select"/"update" 等英文单词误命中。 **宽松模式**(高召回,用于初步扫描): ``` (?i)\\b(select|insert|update|delete)\\b ``` 仅匹配动词,需人工复核排除误报。 **含 DDL**(建表/改表场景): ``` (?i)\\b(select|insert|update|delete|create|alter|drop|merge|truncate)\\b.*\\b(from|into|set|table|index|view)\\b ``` ### MCP 工具对照 | MCP 工具 | 用途 | 场景 | |----------|------|------| | `find_code_by_rule` | YAML rule 搜索项目代码 | **主力**:SQL 抽取、拼接点识别 | | `find_code` | 简单 pattern 搜索 | 快速抽查单文件、验证语法 | | `test_match_code_rule` | 测试 rule 是否匹配给定代码 | **步骤 2 必用**:验证规则正确性 | | `dump_syntax_tree` | 查看代码的 AST/CST 结构 | 调试 pattern、确认节点 kind | ### MCP vs CLI 选择指南 | 维度 | MCP 模式 | CLI 模式 |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub