<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>SqlParserX Blog</title>
        <link>https://dtstack.github.io/SqlParserX/en/blog</link>
        <description>SqlParserX Blog</description>
        <lastBuildDate>Mon, 28 Sep 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[SqlParserX 的诞生起源背景与内部改造]]></title>
            <link>https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx</link>
            <guid>https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx</guid>
            <pubDate>Mon, 28 Sep 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[记录从「为什么要做 SQL 解析」到「在大量异构数据源下如何统一解析」的思考过程，以及最终促成一个纯 Druid 实现的开源 SQL 解析项目诞生的背景。]]></description>
            <content:encoded><![CDATA[<blockquote>
<p>作者：changlu ｜ 日期：2026-09-28</p>
<p>这是一篇关于 SqlParserX 起源的技术博客。它记录了从「为什么要做 SQL 解析」到「在大量异构数据源下如何统一解析」的思考过程，以及最终促成一个纯 Druid 实现的开源 SQL 解析项目诞生的背景。
项目地址与使用方式见 <a href="https://github.com/DTStack/SqlParserX" target="_blank" rel="noopener noreferrer" class="">SqlParserX 仓库</a>，双层架构设计见 <a class="" href="https://dtstack.github.io/SqlParserX/en/docs/about/architecture">架构设计</a>。</p>
</blockquote>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一为什么需要懂解析器">一、为什么需要懂解析器<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#%E4%B8%80%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9C%80%E8%A6%81%E6%87%82%E8%A7%A3%E6%9E%90%E5%99%A8" class="hash-link" aria-label="Direct link to 一、为什么需要懂解析器" title="Direct link to 一、为什么需要懂解析器" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="11-什么是解析器">1.1 什么是解析器<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#11-%E4%BB%80%E4%B9%88%E6%98%AF%E8%A7%A3%E6%9E%90%E5%99%A8" class="hash-link" aria-label="Direct link to 1.1 什么是解析器" title="Direct link to 1.1 什么是解析器" translate="no">​</a></h3>
<p>解析器是计算机科学和编程语言领域中至关重要的工具，其核心作用是<strong>将人类可理解的「形式化语言」（如代码、数据格式、表达式等）转换为机器可处理的结构</strong>，从而实现信息的解析、验证和后续处理。</p>
<p>人类使用的语言（无论是编程语言如 Python、数据格式如 JSON，还是查询语句如 SQL）本质是<strong>结构化的字符串</strong>，但机器无法直接理解这种字符串的逻辑含义。</p>
<p>例如，程序员写的 <code>x = (a + b) * 3</code> 是一串字符，但机器需要知道这是「先算 <code>a + b</code>，再乘以 3，最后赋值给 <code>x</code>」的运算逻辑。解析器把这个字符串解析为一棵语法树，再按规则一步步运算。</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 解析器 扫描解析方程 x = (a + b) * 3 得到的语法树 AST</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       </span><span class="token operator" style="color:#393A34">/</span><span class="token plain">   \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">           </span><span class="token operator" style="color:#393A34">/</span><span class="token plain">   \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">+</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token operator" style="color:#393A34">/</span><span class="token plain">   \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">a</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">b</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">解释执行步骤：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">1</span><span class="token plain">、从根节点 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> 开始，表示这是一个赋值操作。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">2</span><span class="token plain">、左子树 x 是赋值目标，右子树 </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> 是计算内容。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">3</span><span class="token plain">、计算 </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> 时，先计算左子树 </span><span class="token operator" style="color:#393A34">+</span><span class="token plain">（a </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> b），再乘以右子树 </span><span class="token number" style="color:#36acaa">3</span><span class="token plain">。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">4</span><span class="token plain">、最后将结果赋值给 x。</span><br></div></code></pre></div></div>
<p>编程语言同理，如 C、Java 等都有特定的语法规则，通过解析器把代码转为 AST 语法树，再编译字节码、机器码来执行。</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 解析器 扫描解析 Java 代码 if (x &gt; 0) { y = 10; } 得到的语法树 AST</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">       </span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">if</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token operator" style="color:#393A34">/</span><span class="token plain">    \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">block</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token operator" style="color:#393A34">/</span><span class="token plain">   \       \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">x</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">=</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token operator" style="color:#393A34">/</span><span class="token plain">   \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">          </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">y</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">解析执行步骤：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">1</span><span class="token plain">、根节点 </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> 表示条件判断。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">2</span><span class="token plain">、先计算条件 </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain">（x </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain">），如果为真：</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">3</span><span class="token plain">、进入 block 执行内部语句 y </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">10</span><span class="token plain">。</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">4</span><span class="token plain">、如果为假，跳过整个 block。</span><br></div></code></pre></div></div>
<p><strong>解析器的作用</strong>，就是把这种字符串「拆解」为有意义的语法结构（如抽象语法树 AST），让机器能按规则执行。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="12-如何实现解析器">1.2 如何实现解析器<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#12-%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E8%A7%A3%E6%9E%90%E5%99%A8" class="hash-link" aria-label="Direct link to 1.2 如何实现解析器" title="Direct link to 1.2 如何实现解析器" translate="no">​</a></h3>
<p>在编译器实现中，主要要做的是<strong>词法分析和语法分析</strong>：</p>
<ul>
<li class=""><strong>词法分析</strong>：解析代码并生成 Token（一个单词的字面和它的种类及语义值）序列，实现一般称为扫描器（Scanner）。核心逻辑是定义 token（语义）与 scanner（扫描 token）。</li>
<li class=""><strong>语法分析</strong>：利用扫描器生成的 Token 序列生成抽象语法树，实现一般称为解析器（Parser）。核心逻辑是进行语法检查，并构建由输入单词组成的层次化数据结构（语法分析树、抽象语法树等）。</li>
</ul>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">数学表达式：</span><span class="token number" style="color:#36acaa">1</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 首先在进行词法、语法分析前，我们先定义好 token</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">单词字面   Token 类型   说明</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">1</span><span class="token plain">          </span><span class="token keyword" style="color:#00009f">INTEGER</span><span class="token plain">     整数 </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">+</span><span class="token plain">          ADD_OP      加法运算符</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">2</span><span class="token plain">          </span><span class="token keyword" style="color:#00009f">INTEGER</span><span class="token plain">     整数 </span><span class="token number" style="color:#36acaa">2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">*</span><span class="token plain">          MUL_OP      乘法运算符</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token number" style="color:#36acaa">3</span><span class="token plain">          </span><span class="token keyword" style="color:#00009f">INTEGER</span><span class="token plain">     整数 </span><span class="token number" style="color:#36acaa">3</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 1、词法分析：从前往后扫描得到一组 Token 流</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">[</span><span class="token keyword" style="color:#00009f">INTEGER</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ADD_OP</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">+</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTEGER</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> MUL_OP</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTEGER</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">3</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 2、语法分析：根据运算符优先级（* 优先于 +）和 Token 流构建 AST</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">+</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token operator" style="color:#393A34">/</span><span class="token plain">   \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token number" style="color:#36acaa">1</span><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token operator" style="color:#393A34">/</span><span class="token plain">   \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token number" style="color:#36acaa">2</span><span class="token plain">     </span><span class="token number" style="color:#36acaa">3</span><br></div></code></pre></div></div>
<p>实现一种规则的解析器有两种方式：</p>
<ul>
<li class=""><strong>方式一</strong>：不依赖任何工具，手写扫描器和解析器。</li>
<li class=""><strong>方式二</strong>：使用现成的解析器生成器（Yacc、ANTLR、JavaCC 等），根据自定义语法规则文件自动生成解析器代码，从而专注于语法规则设计。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="13-什么是-sql-解析器">1.3 什么是 SQL 解析器<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#13-%E4%BB%80%E4%B9%88%E6%98%AF-sql-%E8%A7%A3%E6%9E%90%E5%99%A8" class="hash-link" aria-label="Direct link to 1.3 什么是 SQL 解析器" title="Direct link to 1.3 什么是 SQL 解析器" translate="no">​</a></h3>
<p>SQL 解析器是<strong>能够将 SQL 语句转换为计算机可理解和执行结构的程序组件</strong>。它将文本形式的 SQL 转换为抽象语法树（AST），为后续的查询优化和执行提供基础。通俗地说，就是能对 SQL 进行解析、转换成语法树的工具。</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># 查询</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> users </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">status</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'active'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 插入</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INTO</span><span class="token plain"> customers </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> email</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'李四'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'lisi@example.com'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 更新</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">UPDATE</span><span class="token plain"> products </span><span class="token keyword" style="color:#00009f">SET</span><span class="token plain"> price </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">5999</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1001</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 删除</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">DELETE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">FROM</span><span class="token plain"> logs </span><span class="token keyword" style="color:#00009f">WHERE</span><span class="token plain"> create_time </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'2024-01-01'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 创建表</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> employees </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id </span><span class="token keyword" style="color:#00009f">INT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">PRIMARY</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">KEY</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> name </span><span class="token keyword" style="color:#00009f">VARCHAR</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">50</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> salary </span><span class="token keyword" style="color:#00009f">DECIMAL</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">10</span><span class="token punctuation" style="color:#393A34">,</span><span class="token number" style="color:#36acaa">2</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 修改表</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">ALTER</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> employees </span><span class="token keyword" style="color:#00009f">ADD</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">COLUMN</span><span class="token plain"> department </span><span class="token keyword" style="color:#00009f">VARCHAR</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">20</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 删除表</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">DROP</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> temp_data</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># 授权</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">GRANT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">SELECT</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">ON</span><span class="token plain"> customers </span><span class="token keyword" style="color:#00009f">TO</span><span class="token plain"> user1</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="14-sql-解析位于整条链路的哪个位置">1.4 SQL 解析位于整条链路的哪个位置<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#14-sql-%E8%A7%A3%E6%9E%90%E4%BD%8D%E4%BA%8E%E6%95%B4%E6%9D%A1%E9%93%BE%E8%B7%AF%E7%9A%84%E5%93%AA%E4%B8%AA%E4%BD%8D%E7%BD%AE" class="hash-link" aria-label="Direct link to 1.4 SQL 解析位于整条链路的哪个位置" title="Direct link to 1.4 SQL 解析位于整条链路的哪个位置" translate="no">​</a></h3>
<p>常见数据库执行 SQL 的整个过程：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SQL文本 → 词法分析（Tokenizer）→ 语法分析（Parser）→ AST → 语义分析 → 优化SQL → 产生执行计划/执行任务</span><br></div></code></pre></div></div>
<p>而 SQL 解析中间件关注的是 AST 之后的应用层能力：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SQL文本 → 词法分析（Tokenizer）→ 语法分析（Parser）→ AST → 应用层（类型识别、表字段血缘、表解析、SQL脱敏）→ 子产品应用</span><br></div></code></pre></div></div>
<p><strong>这正是 SqlParserX 的定位</strong>：不重复实现数据库引擎，只基于一套统一的 AST，把「表、血缘、函数、权限改写」等解析能力做成可复用的中间件。</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="二市面上常见的-sql-解析方案">二、市面上常见的 SQL 解析方案<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#%E4%BA%8C%E5%B8%82%E9%9D%A2%E4%B8%8A%E5%B8%B8%E8%A7%81%E7%9A%84-sql-%E8%A7%A3%E6%9E%90%E6%96%B9%E6%A1%88" class="hash-link" aria-label="Direct link to 二、市面上常见的 SQL 解析方案" title="Direct link to 二、市面上常见的 SQL 解析方案" translate="no">​</a></h2>
<p>在动手之前，我们先横向比较了主流方案。</p>
<p><img decoding="async" loading="lazy" alt="市面上常见的解析器整体介绍" src="https://dtstack.github.io/SqlParserX/en/assets/images/01-parser-market-69347f790ddfccf38bcd49b4df85e909.png" width="2884" height="1540" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="21-底层解析器件javacc--antlr-3--antlr-4">2.1 底层解析器件：JavaCC / ANTLR 3 / ANTLR 4<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#21-%E5%BA%95%E5%B1%82%E8%A7%A3%E6%9E%90%E5%99%A8%E4%BB%B6javacc--antlr-3--antlr-4" class="hash-link" aria-label="Direct link to 2.1 底层解析器件：JavaCC / ANTLR 3 / ANTLR 4" title="Direct link to 2.1 底层解析器件：JavaCC / ANTLR 3 / ANTLR 4" translate="no">​</a></h3>
<table><thead><tr><th>特性</th><th>JavaCC</th><th>ANTLR 3</th><th>ANTLR 4</th></tr></thead><tbody><tr><td>语法分析算法</td><td>LL(k)</td><td>LL(*)</td><td>LL(*)（自适应预测）</td></tr><tr><td>左递归处理</td><td>不支持，需手动转换</td><td>需手动转换</td><td>自动处理</td></tr><tr><td>目标语言</td><td>Java</td><td>Java、C#、Python 等</td><td>同 ANTLR 3</td></tr><tr><td>错误处理</td><td>基础错误恢复</td><td>增强的错误恢复</td><td>智能错误恢复与诊断</td></tr><tr><td>语法复杂度</td><td>简单直观</td><td>较复杂</td><td>简化（相比 ANTLR 3）</td></tr><tr><td>应用场景</td><td>小型项目、教育</td><td>中大型项目</td><td>大型项目、复杂语法</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="22-sql-解析器脚手架calcite--hive-exec">2.2 SQL 解析器脚手架：Calcite / hive-exec<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#22-sql-%E8%A7%A3%E6%9E%90%E5%99%A8%E8%84%9A%E6%89%8B%E6%9E%B6calcite--hive-exec" class="hash-link" aria-label="Direct link to 2.2 SQL 解析器脚手架：Calcite / hive-exec" title="Direct link to 2.2 SQL 解析器脚手架：Calcite / hive-exec" translate="no">​</a></h3>
<p>所谓脚手架，是基于 JavaCC 或 ANTLR 已经实现了标准 SQL 的词法、语法规则，我们只需按其规范扩展：</p>
<ul>
<li class=""><strong>Calcite（基于 JavaCC）</strong>：模块化、可扩展的 SQL 解析与优化框架，很多开源 SQL 引擎用它来做标准 SQL 解析与优化。</li>
<li class=""><strong>hive-exec（基于 ANTLR3）</strong>：Hive 的核心包，支持 Hive/Spark 语法解析。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="23-更具象化的解析器jsqlparser--druid">2.3 更「具象化」的解析器：JSqlParser / Druid<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#23-%E6%9B%B4%E5%85%B7%E8%B1%A1%E5%8C%96%E7%9A%84%E8%A7%A3%E6%9E%90%E5%99%A8jsqlparser--druid" class="hash-link" aria-label="Direct link to 2.3 更「具象化」的解析器：JSqlParser / Druid" title="Direct link to 2.3 更「具象化」的解析器：JSqlParser / Druid" translate="no">​</a></h3>
<ul>
<li class=""><strong>JSqlParser</strong>：基于 JavaCC，能将 SQL 转为更语义化的结构（如 <code>select</code> → <code>SelectStatement</code>），支持语法树类继承、JavaAPI 构建 SQL、语法树转 SQL；但 <strong>API 无明显的特定方言解析分层，支持的数据源解析能力较弱</strong>。</li>
<li class=""><strong>Druid</strong>：完全用 Java 自实现扫描器、解析器，解析出的语法树是<strong>具象化的抽象语法树（具有继承关系）</strong>，并且<strong>支持按数据源分层扩展</strong>（Lexer、Parser 扫描可分层隔离）。</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="24-核心对比与选型结论">2.4 核心对比与选型结论<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#24-%E6%A0%B8%E5%BF%83%E5%AF%B9%E6%AF%94%E4%B8%8E%E9%80%89%E5%9E%8B%E7%BB%93%E8%AE%BA" class="hash-link" aria-label="Direct link to 2.4 核心对比与选型结论" title="Direct link to 2.4 核心对比与选型结论" translate="no">​</a></h3>
<table><thead><tr><th>工具</th><th>依赖工具</th><th>解析 SQL 能力</th><th>语法树类继承</th><th>优缺点</th></tr></thead><tbody><tr><td>JavaCC</td><td>原生定义解析规则</td><td>无</td><td>无</td><td>需从零定义 SQL 规则</td></tr><tr><td>ANTLR4</td><td>原生定义解析规则</td><td>有，官方语法生态极好</td><td>无</td><td>语法生态强，但解析语法树无抽象继承关系</td></tr><tr><td>Calcite</td><td>基于 JavaCC</td><td>标准 SQL，多方言扩展、生态较弱</td><td>有</td><td>需手动扩展分层写语法规则，成本大</td></tr><tr><td>hive-exec</td><td>基于 ANTLR3</td><td>仅 Hive、Spark</td><td>无</td><td>无法扩展分层到其他数据源</td></tr><tr><td>JSqlParser</td><td>基于 JavaCC</td><td>标准 SQL，部分方言</td><td>有</td><td>API 无明显数据源分层</td></tr><tr><td><strong>Druid</strong></td><td>原生 Java 实现扫描、解析器件</td><td>支持 MySQL、Oracle、Hive、Spark、Doris、StarRocks 等</td><td><strong>有（极强）</strong></td><td>数据源生态好、AST 有继承关系；缺点是 Java 自实现扫描器，入门有难度</td></tr></tbody></table>
<p>面向数栈「大量异构数据源都要有同样继承关系的语法树」的场景，需要抽象定义统一的 <code>Insert</code>、<code>Select</code>、<code>Update</code>、<code>Delete</code> 等结构。</p>
<p><strong>基于 Druid 这样一套有继承关系的 AST，不同功能只需实现一套解析逻辑即可对应所有数据源，部分数据源再单独通过分层兼容即可。</strong> 这成为后续选型的决定性理由。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="25-为什么不直接用-antlr4">2.5 为什么不直接用 ANTLR4<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#25-%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E7%9B%B4%E6%8E%A5%E7%94%A8-antlr4" class="hash-link" aria-label="Direct link to 2.5 为什么不直接用 ANTLR4" title="Direct link to 2.5 为什么不直接用 ANTLR4" translate="no">​</a></h3>
<p>ANTLR4 生态确实很好（官方有 grammars-v4），但它的语法树<strong>没有抽象继承关系</strong>，难以在多数据源上沉淀「一套业务解析逻辑」，需要在业务层重新抽象一套结构，反而增加维护成本。Druid 的 AST 天然带继承体系，更契合我们的目标。</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="三历史背景改造前的-sql-解析为什么难维护">三、历史背景：改造前的 SQL 解析为什么难维护<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#%E4%B8%89%E5%8E%86%E5%8F%B2%E8%83%8C%E6%99%AF%E6%94%B9%E9%80%A0%E5%89%8D%E7%9A%84-sql-%E8%A7%A3%E6%9E%90%E4%B8%BA%E4%BB%80%E4%B9%88%E9%9A%BE%E7%BB%B4%E6%8A%A4" class="hash-link" aria-label="Direct link to 三、历史背景：改造前的 SQL 解析为什么难维护" title="Direct link to 三、历史背景：改造前的 SQL 解析为什么难维护" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="31-子产品各自为战">3.1 子产品各自为战<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#31-%E5%AD%90%E4%BA%A7%E5%93%81%E5%90%84%E8%87%AA%E4%B8%BA%E6%88%98" class="hash-link" aria-label="Direct link to 3.1 子产品各自为战" title="Direct link to 3.1 子产品各自为战" translate="no">​</a></h3>
<p>改造前，SQL 解析散落在多个子产品中，各用各的方案：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">离线 batchparser：</span><span class="token keyword" style="color:#00009f">SQL</span><span class="token plain"> 类型识别、真实表解析、</span><span class="token keyword" style="color:#00009f">SQL</span><span class="token plain"> 脱敏、行列级权限</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  面向 </span><span class="token keyword" style="color:#00009f">SQL</span><span class="token plain"> 类型：rdb（mysql、oracle、doris</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">）、hive、spark、impala</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  实现：calcite </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> hive</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">exec</span><span class="token plain"> 模块解析器，加上 druid 兜底【中间各种兼容语法正则匹配替换逻辑】</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">API apiparser：API 解析（预编译、非预编译）、真实表解析、行列级权限</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  面向 </span><span class="token keyword" style="color:#00009f">SQL</span><span class="token plain"> 类型：rdb</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  实现：calcite </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> druid，druid 兜底</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">label labelparser：标签解析</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  实现：calcite</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">实时 streamparser</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  StreamCreateTableParser 直接使用正则匹配解析</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  StreamCreateViewParser 使用 hive</span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">exec</span><span class="token plain"> 进行表、字段血缘解析</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  StreamInsertParser 使用 FlinkPlanner </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain"> hive parser 进行表、字段血缘解析</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">资产 sqlparser：表、字段血缘解析、真实表解析、</span><span class="token keyword" style="color:#00009f">SQL</span><span class="token plain"> 类型识别</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  实现：比较混乱，calcite、druid 以及 hive parser 混用</span><br></div></code></pre></div></div>
<p>核心问题是：<strong>历史上针对 SQL 语法层面的扩展很少</strong>，导致语法解析「一个不行就换另一个」，各种兜底；做过语法扩展的主要是基于 Calcite 扩展了少量语法（limit、starrocks 等）。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="32-历史设计架构">3.2 历史设计架构<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#32-%E5%8E%86%E5%8F%B2%E8%AE%BE%E8%AE%A1%E6%9E%B6%E6%9E%84" class="hash-link" aria-label="Direct link to 3.2 历史设计架构" title="Direct link to 3.2 历史设计架构" translate="no">​</a></h3>
<p>改造前主要针对 Calcite（rdb 类型）、hive-exec（spark、hive）两类 SQL，Druid 与正则方式作为兜底。</p>
<p><img decoding="async" loading="lazy" alt="改造前的历史设计架构" src="https://dtstack.github.io/SqlParserX/en/assets/images/02-legacy-architecture-8c0e245dcac8e3570e5a686b9f58b9d9.png" width="16384" height="5838" class="img_ev3q"></p>
<p>业务逻辑可以分为两类：</p>
<p><strong>一类：SQL 类型识别、表解析、SQL 脱敏、行列级权限</strong></p>
<ol>
<li class="">根据 SQL 类型用 Calcite、hive-exec 解析得到语法树；</li>
<li class="">基于语法树做上述业务。</li>
</ol>
<p><strong>另一类：血缘实现</strong></p>
<ol>
<li class="">用 Calcite、hive-exec 解析得到语法树；</li>
<li class=""><strong>自定义语法树</strong>，实现两套转换器（Calcite AST → 自定义 AST、hive-exec AstNode → 自定义 AST）；</li>
<li class="">针对自定义语法树写一套血缘解析逻辑。</li>
</ol>
<blockquote>
<p>问题：转换与解析扫描过程中，历史上曾出现死循环导致子产品服务挂掉等各种情况。</p>
</blockquote>
<p><img decoding="async" loading="lazy" alt="Calcite 分层扩展文章的探索" src="https://dtstack.github.io/SqlParserX/en/assets/images/03-calcite-layered-article-1d0e86b355eba0e53d237d95afd4d3a6.png" width="1710" height="852" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="33-主要问题">3.3 主要问题<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#33-%E4%B8%BB%E8%A6%81%E9%97%AE%E9%A2%98" class="hash-link" aria-label="Direct link to 3.3 主要问题" title="Direct link to 3.3 主要问题" translate="no">​</a></h3>
<ol>
<li class=""><strong>不同数据源语法解析扩展能力弱</strong>：不同 rdb 语法需要正则前置处理，或单独去扩展语法，且扩展语法集中在一个模块；</li>
<li class=""><strong>使用多种解析框架、各种兜底，代码维护难</strong>：拿到语法树后的应用层解析逻辑也冗余在一起，到处是 <code>if</code> 判断数据源兼容逻辑，改一个地方可能影响其他地方，难以维护；</li>
<li class=""><strong>血缘解析扩展弱、学习成本极高</strong>：需要先了解 Calcite / AstNode 的节点定义，再具备自定义语法树能力，然后扩展两层转换逻辑（还容易死循环），最后才到血缘解析本身。</li>
</ol>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="四技术改造双层分层">四、技术改造：双层分层<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#%E5%9B%9B%E6%8A%80%E6%9C%AF%E6%94%B9%E9%80%A0%E5%8F%8C%E5%B1%82%E5%88%86%E5%B1%82" class="hash-link" aria-label="Direct link to 四、技术改造：双层分层" title="Direct link to 四、技术改造：双层分层" translate="no">​</a></h2>
<p>技术改造围绕两个层面分层：<strong>语法解析层</strong> 与 <strong>业务解析层</strong>。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="41-语法解析层基于-druid">4.1 语法解析层（基于 Druid）<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#41-%E8%AF%AD%E6%B3%95%E8%A7%A3%E6%9E%90%E5%B1%82%E5%9F%BA%E4%BA%8E-druid" class="hash-link" aria-label="Direct link to 4.1 语法解析层（基于 Druid）" title="Direct link to 4.1 语法解析层（基于 Druid）" translate="no">​</a></h3>
<p><img decoding="async" loading="lazy" alt="语法解析层分层" src="https://dtstack.github.io/SqlParserX/en/assets/images/04-druid-syntax-layer-815515eac5295f9f772e1beb97f04c11.png" width="2120" height="712" class="img_ev3q"></p>
<p>分层实现后，扫描器、解析器都支持继承复用，且相互独立、互不影响，结构类可自定义扩展：</p>
<p><img decoding="async" loading="lazy" alt="Druid 分层结构类" src="https://dtstack.github.io/SqlParserX/en/assets/images/05-druid-layer-structure-5737c5a7826cff1a2874cf2b927ccd34.png" width="3080" height="1824" class="img_ev3q"></p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 工具类指定数据源类型实现解析</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">SQLStatementParser</span><span class="token plain"> parser </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">SQLParserUtils</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">createSQLStatementParser</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sql</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">DbType</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">doris</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">SQLStatement</span><span class="token plain"> statement </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> parser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">parseStatement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 或直接 new 特定 Parser</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">DorisStatementParser</span><span class="token plain"> statementParser </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">DorisStatementParser</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sql</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">SQLStatement</span><span class="token plain"> sqlStatement </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> statementParser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">parseStatement</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="42-业务解析层">4.2 业务解析层<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#42-%E4%B8%9A%E5%8A%A1%E8%A7%A3%E6%9E%90%E5%B1%82" class="hash-link" aria-label="Direct link to 4.2 业务解析层" title="Direct link to 4.2 业务解析层" translate="no">​</a></h3>
<ul>
<li class=""><strong>解析层</strong>：不同数据源 → 统一抽象结构语法树；</li>
<li class=""><strong>应用层</strong>：针对统一 AST 实现一套解析方法；特定数据源在 AST 中自定义了部分节点时，应用层再针对该数据源的节点做分层处理。</li>
</ul>
<p><img decoding="async" loading="lazy" alt="业务解析分层" src="https://dtstack.github.io/SqlParserX/en/assets/images/06-business-layer-46c84fa8b5f3c12f0316fc058e9daf15.png" width="3972" height="2296" class="img_ev3q"></p>
<p>针对抽象语法树实现通用解析组件：</p>
<p><img decoding="async" loading="lazy" alt="应用层通用解析组件" src="https://dtstack.github.io/SqlParserX/en/assets/images/07-application-components-3fa01967e1605c21791788f2a06212eb.png" width="9256" height="1888" class="img_ev3q"></p>
<p>后续扩展时，若在语法层单独实现了某个节点，只需继承 <code>BaseXxxClient</code>，单独实现差异方法即可，重复逻辑复用：</p>
<p><img decoding="async" loading="lazy" alt="继承 BaseXxxClient 扩展" src="https://dtstack.github.io/SqlParserX/en/assets/images/08-inherit-baseclient-cb4fb84bd3af91ceb7d6b08e4ec7d466.png" width="2324" height="1252" class="img_ev3q"></p>
<p>创建 Client 后，在对应 <code>XxxSqlParser</code> 中注册：</p>
<p><img decoding="async" loading="lazy" alt="在方言解析器中注册 Client" src="https://dtstack.github.io/SqlParserX/en/assets/images/09-register-client-c6216b08439b96af51fda129de838a4e.png" width="2100" height="648" class="img_ev3q"></p>
<p>示例：</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// 准备 SQL</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">String</span><span class="token plain"> sql </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getSql</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 1、获取解析器（工厂方式）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">ISqlParser</span><span class="token plain"> sqlParser </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">SqlParserFactory</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getSqlParser</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">DbType</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">mysql</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 2.1、解析表</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">ParseTableResult</span><span class="token plain"> parseTableResult </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> sqlParser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">parseTables</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sql</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parseTableResult</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getMainTable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">   </span><span class="token comment" style="color:#999988;font-style:italic">// 主表</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">out</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">parseTableResult</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getAllTableName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 所有表</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 2.2、解析字段血缘（select * 场景可传入 tableColumnsMap 提供字段元数据）</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">ColumnLineageResult</span><span class="token plain"> columnLineageResult </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> sqlParser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">parseColumnLineages</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sql</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> tableColumnsMap</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 2.3、解析表血缘</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">TableLineageResult</span><span class="token plain"> tableLineageResult </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> sqlParser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">parseTableLineages</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sql</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 2.4、解析函数</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Set</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> functions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> sqlParser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">parseFunction</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">sql</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="43-改造后整体实现">4.3 改造后整体实现<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#43-%E6%94%B9%E9%80%A0%E5%90%8E%E6%95%B4%E4%BD%93%E5%AE%9E%E7%8E%B0" class="hash-link" aria-label="Direct link to 4.3 改造后整体实现" title="Direct link to 4.3 改造后整体实现" translate="no">​</a></h3>
<p>后续语法解析、业务层解析都可独立扩展：</p>
<p><img decoding="async" loading="lazy" alt="改造后整体实现" src="https://dtstack.github.io/SqlParserX/en/assets/images/10-after-refactor-c8b89cd447d9cea7894354ffea6a2fdf.png" width="5684" height="2764" class="img_ev3q"></p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="五业务层解析的重新实现">五、业务层解析的重新实现<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#%E4%BA%94%E4%B8%9A%E5%8A%A1%E5%B1%82%E8%A7%A3%E6%9E%90%E7%9A%84%E9%87%8D%E6%96%B0%E5%AE%9E%E7%8E%B0" class="hash-link" aria-label="Direct link to 五、业务层解析的重新实现" title="Direct link to 五、业务层解析的重新实现" translate="no">​</a></h2>
<p>历史上基于 Druid 的业务层实现很少（仅 API 解析、离线部分解析用 Druid 兜底），因此表解析、血缘解析都需要重新实现。</p>
<p><strong>有血缘特征的 SQL 类型</strong>：<code>insert into/overwrite ... select</code>、<code>create ... select</code>、<code>with as ... insert</code>。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="51-字段血缘解析">5.1 字段血缘解析<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#51-%E5%AD%97%E6%AE%B5%E8%A1%80%E7%BC%98%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="Direct link to 5.1 字段血缘解析" title="Direct link to 5.1 字段血缘解析" translate="no">​</a></h3>
<p>核心思路是<strong>把来源与目标各自归一为一张二维表</strong>。</p>
<p>以一条 <code>insert select</code> 为例：</p>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">insert</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">into</span><span class="token plain"> new_table </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">select</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">id </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> aid</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">name </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> bname</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> old_table </span><span class="token keyword" style="color:#00009f">as</span><span class="token plain"> a</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">left</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">join</span><span class="token plain"> old_table2 b </span><span class="token keyword" style="color:#00009f">on</span><span class="token plain"> a</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">id </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> b</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">id</span><br></div></code></pre></div></div>
<ol>
<li class="">拆成两个部分：<code>insert</code> 目标端、<code>select</code> 来源端；</li>
<li class="">各自追溯得到一组列表：</li>
</ol>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 目标端</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">真实字段   别名字段   真实表名</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  id        id       new_table</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  name      name     new_table</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 来源端</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">真实字段   别名字段   真实表名</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  id       aid       old_table</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  name     bname     old_table2</span><br></div></code></pre></div></div>
<ol start="3">
<li class="">两组按固定规则匹配，即得字段血缘：</li>
</ol>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 第一条</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">admin 目标端 new_table.id  ←  来源端 old_table.id</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 第二条</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">目标端 new_table.name      ←  来源端 old_table2.name</span><br></div></code></pre></div></div>
<p>来源端的「真实表名 → 来源表」「真实字段 → 来源字段」，目标端的「别名字段 → 目标字段」。</p>
<p>对于 <code>with as</code> 场景，每个 CTE 的 <code>()</code> 作为一组同样归一为二维表再匹配；对于<strong>单列来源于多字段</strong>的场景（如 <code>concat(t1.name, t2.name)</code>），真实字段与真实表名以 <code>,</code> 合并，最终拆成多条血缘。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="52-表血缘解析">5.2 表血缘解析<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#52-%E8%A1%A8%E8%A1%80%E7%BC%98%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="Direct link to 5.2 表血缘解析" title="Direct link to 5.2 表血缘解析" translate="no">​</a></h3>
<p>本质与字段血缘类似，更多是对表进行分组列表，一个 <code>select</code> 同样得到一组「表、表别名」的二维表，最终与 <code>insert</code> 目标表匹配即可完成表血缘。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="53-表解析">5.3 表解析<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#53-%E8%A1%A8%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="Direct link to 5.3 表解析" title="Direct link to 5.3 表解析" translate="no">​</a></h3>
<p>与表血缘类似，需要解析出所有真实表；除了追溯真实表的过程，还要合并没有被追溯到的真实表，同时覆盖比表血缘更多的 SQL 结构（<code>select</code>、<code>update</code>、<code>delete</code>、<code>insert</code>、<code>drop</code>、<code>rename</code> 等）。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="54-函数解析">5.4 函数解析<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#54-%E5%87%BD%E6%95%B0%E8%A7%A3%E6%9E%90" class="hash-link" aria-label="Direct link to 5.4 函数解析" title="Direct link to 5.4 函数解析" translate="no">​</a></h3>
<p>函数与血缘无关，直接使用 <strong>Visitor 模式</strong>收集所有函数即可：</p>
<p><img decoding="async" loading="lazy" alt="基于 Visitor 的函数解析" src="https://dtstack.github.io/SqlParserX/en/assets/images/11-function-visitor-43a9830686ce367f536545b5691f504f.png" width="2150" height="1224" class="img_ev3q"></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="55-其他业务能力">5.5 其他业务能力<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#55-%E5%85%B6%E4%BB%96%E4%B8%9A%E5%8A%A1%E8%83%BD%E5%8A%9B" class="hash-link" aria-label="Direct link to 5.5 其他业务能力" title="Direct link to 5.5 其他业务能力" translate="no">​</a></h3>
<ul>
<li class=""><strong>SQL 脱敏（离线）</strong>：复用字段血缘的 select column 组件拿到字段列表，再结合语法层位点能力进行改写；难点是 Druid 无精确原始 SQL 位点，需要扩展。</li>
<li class=""><strong>行级权限改写 SQL</strong>：利用 Druid API 补充 AST 节点，再转回 SQL，本质是根据主体 select 封装/补充条件节点后重新输出。</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="六sqlparserx-的诞生">六、SqlParserX 的诞生<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#%E5%85%ADsqlparserx-%E7%9A%84%E8%AF%9E%E7%94%9F" class="hash-link" aria-label="Direct link to 六、SqlParserX 的诞生" title="Direct link to 六、SqlParserX 的诞生" translate="no">​</a></h2>
<p>在内部双层改造验证落地之后，一个更清晰的想法出现了：<strong>能不能把「基于 Druid 的 SQL 解析」做成一个纯净、可独立演进的开源项目？</strong></p>
<p>于是有了 <strong>SqlParserX</strong> —— 一个无需依赖 Calcite、ANTLR 等其他解析组件，<strong>完全基于 Druid 实现各类不同 SQL 解析</strong>的开源项目。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="61-双层架构">6.1 双层架构<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#61-%E5%8F%8C%E5%B1%82%E6%9E%B6%E6%9E%84" class="hash-link" aria-label="Direct link to 6.1 双层架构" title="Direct link to 6.1 双层架构" translate="no">​</a></h3>
<p>SqlParserX 将解析内核拆分为两个独立 Jar Module，结构对称、职责清晰：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">SqlParserX（根 Reactor）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── sqlparserx-engine（聚合父模块，packaging=pom）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   ├── sqlparserx-syntax（jar，语法解析层，基于 Druid）    ← 只管 SQL → AST</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── sqlparserx-core（jar，业务解析层，依赖 syntax）     ← 只管 AST → 业务结果</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── sqlparserx-web（HTTP 服务）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── sqlparserx-mcp-server-sse（MCP Server）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── sqlparserx-ui（前端）</span><br></div></code></pre></div></div>
<ul>
<li class=""><strong>语法解析层（<code>sqlparserx-syntax</code>）</strong>：统一维护 Druid 依赖、SQL→AST、多语句解析与切分，以及后续数据源 Lexer / StatementParser / AST Node 扩展；</li>
<li class=""><strong>业务解析层（<code>sqlparserx-core</code>）</strong>：基于统一 AST 实现真实表、建表结构、表/字段血缘、函数与 SQL 权限改写。</li>
</ul>
<p>两层以 <code>DbType + SQLStatement AST</code> 作为连接契约，<strong>不额外复制一套 AST</strong>，避免长期转换与同步。详细设计见 <a href="https://github.com/DTStack/SqlParserX/blob/master/docs/02%E3%80%81SQL%E4%B8%9A%E5%8A%A1%E5%B1%82%E8%A7%A3%E6%9E%90%E8%83%BD%E5%8A%9B%E6%94%AF%E6%92%91%E6%83%85%E5%86%B5/%E6%A8%A1%E5%9D%97%E4%BE%9D%E8%B5%96%E5%8C%85%E5%BC%95%E7%94%A8%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1.md" target="_blank" rel="noopener noreferrer" class="">模块依赖包引用结构设计</a>。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="62-从内部二开走向官方-druid">6.2 从内部二开走向官方 Druid<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#62-%E4%BB%8E%E5%86%85%E9%83%A8%E4%BA%8C%E5%BC%80%E8%B5%B0%E5%90%91%E5%AE%98%E6%96%B9-druid" class="hash-link" aria-label="Direct link to 6.2 从内部二开走向官方 Druid" title="Direct link to 6.2 从内部二开走向官方 Druid" translate="no">​</a></h3>
<p>项目早期依赖内部二开的 Druid 版本，随着能力沉淀，SqlParserX 已统一为<strong>官方 Druid 1.2.28</strong>，降低维护成本、方便社区协作。语法层坚持「<strong>不在业务层用大量正则替换规避语法问题</strong>」，方言语法差异一律回到语法层按 Druid 的方式扩展。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="63-能力与文档体系">6.3 能力与文档体系<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#63-%E8%83%BD%E5%8A%9B%E4%B8%8E%E6%96%87%E6%A1%A3%E4%BD%93%E7%B3%BB" class="hash-link" aria-label="Direct link to 6.3 能力与文档体系" title="Direct link to 6.3 能力与文档体系" translate="no">​</a></h3>
<p>SqlParserX 不仅提供代码，也提供了一套可维护的文档体系：</p>
<ul>
<li class=""><a class="" href="https://dtstack.github.io/SqlParserX/en/docs/about/architecture">双层架构设计</a></li>
<li class=""><a href="https://github.com/DTStack/SqlParserX/blob/master/docs/02%E3%80%81SQL%E4%B8%9A%E5%8A%A1%E5%B1%82%E8%A7%A3%E6%9E%90%E8%83%BD%E5%8A%9B%E6%94%AF%E6%92%91%E6%83%85%E5%86%B5/%E6%A8%A1%E5%9D%97%E4%BE%9D%E8%B5%96%E5%8C%85%E5%BC%95%E7%94%A8%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1.md" target="_blank" rel="noopener noreferrer" class="">模块依赖包引用结构设计</a></li>
<li class=""><a href="https://github.com/DTStack/SqlParserX/blob/master/docs/01%E3%80%81SQL%E8%AF%AD%E6%B3%95%E5%B1%82%E8%A7%A3%E6%9E%90%E8%83%BD%E5%8A%9B%E6%94%AF%E6%92%91%E6%83%85%E5%86%B5/Druid%E7%89%88%E6%9C%AC%E4%B8%8ESQL%E8%AF%AD%E6%B3%95%E6%94%AF%E6%8C%81%E6%83%85%E5%86%B5.md" target="_blank" rel="noopener noreferrer" class="">Druid 版本与 SQL 语法支持情况</a></li>
<li class=""><a href="https://github.com/DTStack/SqlParserX/tree/master/docs/02%E3%80%81SQL%E4%B8%9A%E5%8A%A1%E5%B1%82%E8%A7%A3%E6%9E%90%E8%83%BD%E5%8A%9B%E6%94%AF%E6%92%91%E6%83%85%E5%86%B5/%E8%83%BD%E5%8A%9B%E6%94%AF%E6%8C%81%E6%83%85%E5%86%B5" target="_blank" rel="noopener noreferrer" class="">能力支持情况（数据源 + 通用解析能力）</a></li>
<li class=""><a href="https://github.com/DTStack/SqlParserX/blob/master/docs/02%E3%80%81SQL%E4%B8%9A%E5%8A%A1%E5%B1%82%E8%A7%A3%E6%9E%90%E8%83%BD%E5%8A%9B%E6%94%AF%E6%92%91%E6%83%85%E5%86%B5/%E6%A0%87%E5%87%86%E8%BF%AD%E4%BB%A3%E7%BB%B4%E6%8A%A4%E6%89%A9%E5%B1%95%E6%96%87%E6%A1%A3/SqlParserX%E8%A7%A3%E6%9E%90%E8%83%BD%E5%8A%9B%E6%A0%87%E5%87%86%E8%BF%AD%E4%BB%A3%E7%BB%B4%E6%8A%A4%E6%89%A9%E5%B1%95%E6%8C%87%E5%8D%97.md" target="_blank" rel="noopener noreferrer" class="">解析能力标准迭代维护扩展指南</a></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="64-目标">6.4 目标<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#64-%E7%9B%AE%E6%A0%87" class="hash-link" aria-label="Direct link to 6.4 目标" title="Direct link to 6.4 目标" translate="no">​</a></h3>
<ul>
<li class="">无需依赖 Calcite、ANTLR 等其他解析组件，<strong>完全基于 Druid</strong> 实现各种数据源的 SQL 解析；</li>
<li class=""><strong>语法问题扩展 Druid，业务语义扩展 SqlParserX</strong>；通用能力沉淀 Base，数据源差异按方言覆盖；</li>
<li class="">新增数据源时，语法差异在语法层扩展，业务差异在业务层扩展，上下两层通过 <code>DbType</code> 与 AST 对齐。</li>
</ul>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="七结语">七、结语<a href="https://dtstack.github.io/SqlParserX/en/blog/origin-of-sqlparserx#%E4%B8%83%E7%BB%93%E8%AF%AD" class="hash-link" aria-label="Direct link to 七、结语" title="Direct link to 七、结语" translate="no">​</a></h2>
<p>从「散落各处的解析器 + 各种兜底」到「统一 AST + 双层分层」，再到「一个纯净、只依赖 Druid 的开源项目」，SqlParserX 的诞生不是一次性的重构，而是一次次把问题放回正确层次的取舍：</p>
<blockquote>
<p><strong>语法问题扩展 Druid，业务语义扩展 SqlParserX；通用能力沉淀 Base，数据源差异按方言覆盖。</strong></p>
</blockquote>
<p>如果你在做多数据源的 SQL 解析、血缘、表解析相关工作，欢迎一起交流与共建。</p>
<hr>
<blockquote>
<p>作者：changlu ｜ 2026-09-28</p>
<p>本文图片位于 <code>assets/</code> 目录，仓库内以相对路径引用。</p>
</blockquote>]]></content:encoded>
            <category>起源与背景</category>
        </item>
    </channel>
</rss>