深度解析JQuick-SQL SQL解析与AST生成机制|分布式SQL原理
Meta 描述:本文拆解jquick-sql架构原理中的SQL解析链路,说明Java分布式SQL引擎架构如何借助ANTLR生成强类型AST,并分析JQuickSQLExecutor、JQuickQueryNode与Visitor协作,为理解SQL查询优化原理及后续gRPC分布式数据交换奠定基础。
标签:jquick-sql架构原理、ANTLR、SQL Parser、强类型AST、Java分布式SQL引擎架构、SQL查询优化原理
官网示例:
- FORMULAS 示例页:https://www.jquick.org/jquick-sql
- github 地址:https://github.com/paohaijiao/jquick-sql
前言
JQuick-SQL 的执行入口并不是把 SQL 字符串直接解释成结果集,而是先把文本转换为可遍历、可校验的抽象语法树(Abstract Syntax Tree,AST)。这一层把语法识别与后续计划生成解耦:Parser 只回答"SQL 写得是否符合文法、结构是什么",Logical Plan 与 Physical Plan 则分别回答"要做什么"和"如何执行"。
项目中的 JQuickSQLExecutor 是该链路的核心入口;它基于 ANTLR 的通用执行器抽象,将 SQL 文本最终产出为 JQuickQueryNode。这种设计使 WHERE、JOIN、GROUP BY、ORDER BY、LIMIT、子查询与 CTE 等结构不再以字符串形式向下传递。
ANTLR解析链路:从字符流到查询树
JQuickSQLExecutor 继承 JAbstractAntlrExecutor<String, JQuickQueryNode>。执行时先由 createLexer 创建 JQuickSQLLexer,再由 createParser 创建 JQuickSQLParser。Parser 的根规则是 query(),其返回的 QueryContext 是 ANTLR 的语法树上下文,而不是项目自己的业务 AST。
java
JQuickSQLParser calcParser = (JQuickSQLParser) parser;
JQuickSQLParser.QueryContext tree = calcParser.query();
JQuickSQLCommonVisistor visitor =
new JQuickSQLCommonVisistor(this.context, this.config);
JQuickQueryNode queryNode = visitor.visitQuery(tree);
这里最关键的是最后两行:JQuickSQLCommonVisistor 遍历 ANTLR 语法树,并将其映射为项目定义的节点对象。Lexer、Parser 与 Visitor 各司其职,避免业务代码依赖 ANTLR 的上下文类型。
强类型AST:JQuickQueryNode为何重要
JQuickQueryNode 是查询 AST 的根节点。解析器模块中还定义了 JQuickSelectStatementNode、JQuickFromClauseNode、JQuickWhereClauseNode、JQuickJoinClauseNode、JQuickGroupByClauseNode、JQuickOrderByClauseNode、JQuickLimitClauseNode 等一组明确的节点类型。
因此,后续组件可以直接根据节点语义处理查询:FROM 对应数据来源,WHERE 对应过滤条件,JOIN 保留连接类型与条件,SELECT 元素保留表达式与别名。相比再次拆分 SQL 字符串,强类型 AST 能让计划生成阶段以结构化对象为输入,并为表达式、函数调用、CASE WHEN、集合操作与子查询保留清晰边界。
Visitor边界与错误定位
ANTLR 负责按文法建立解析上下文,JQuickSQLCommonVisistor 负责组装领域对象。这个边界意味着语法错误应在 Parser 阶段暴露;而"某个节点尚不支持如何计划化"属于 AST 到 Logical Plan 的后续责任。JQuickSQLExecutor 的构造过程还接受 JContext 与 JQuickSqlConfig,使 Visitor 可以在构建 AST 时使用项目上下文,而不会把配置判断散落在调用方。
text
SQL 文本
↓
JQuickSQLLexer → TokenStream → JQuickSQLParser.query()
↓
ANTLR QueryContext
↓
JQuickSQLCommonVisistor
↓
JQuickQueryNode(强类型 AST)
实操代码案例
README 中给出了直接验证 AST 生成的方式:
java
JQuickSQLExecutor executor = new JQuickSQLExecutor();
JQuickQueryNode ast = executor.execute(
"SELECT dept, COUNT(*) FROM emp " +
"WHERE salary > 20000 GROUP BY dept HAVING COUNT(*) > 1"
);
System.out.println(ast);
该例先经过 query() 规则解析,再由 Visitor 生成根节点。示例中的过滤、分组与 HAVING 都是 AST 的结构组成,尚未进入具体扫描、聚合或网络传输执行。
常见问题
AST是否等同于执行计划?
不是。AST 表达 SQL 的语法与语义结构;执行计划会把它转换成 Scan、Filter、Project、Join、Aggregate 等节点。
能否跳过AST直接执行?
项目的公开解析链路以 JQuickSQLExecutor 产出 JQuickQueryNode 为基础;后续计划模块依赖该结构,不应以字符串替代。
ANTLR生成的类可以直接作为业务接口吗?
可以读取,但项目选择通过 Visitor 转成自身节点类型,从而降低后续模块对 ANTLR 上下文的耦合。
总结与拓展
JQuick-SQL 的 Parser 层以 ANTLR 完成词法和语法识别,再通过 JQuickSQLCommonVisistor 将 QueryContext 转换为 JQuickQueryNode。这条链路是 jquick-sql架构原理 的第一段:它把 SQL 文本稳定地变成强类型输入,为逻辑计划、规则优化和分布式执行提供基础。
Core Advantage
ANTLR parsing and a typed AST isolate SQL syntax from planning and execution.
Applicable Scenarios
SQL validation, AST inspection, custom syntax analysis, and plan-building pipelines.