Skip to main content

sql-extract

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

الانتقال إلى التثبيت

معلومات المصدر

المستودع
hellyguo/self-ai-spec
آخر نشاط في المصدر
٢٧ يوليو ٢٠٢٦ في ٠٥:٥٧
لغة SKILL.md المكتشفة
الصينية
النجوم
٨
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
5 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
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 模式 |
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub