ShardingSphere SQL Parser 代码分析
主要功能模块
1. 解析引擎(engine)
- 核心功能:提供SQL解析引擎,包含词法分析和语法分析
- 方言支持:为不同数据库提供专门的解析器实现
2. 服务接口(spi)
- 核心功能:定义SQL解析的抽象接口
- 接口类型:词法分析器、语法分析器、访问器等
3. 语句模型(statement)
- 核心功能:定义解析后SQL语句的数据结构
- 分类:DDL、DML、DCL、TCL、DAL等语句类型
调用方法详解
1. SQL 解析方法入口
主要调用链
SQLParserEngine.parse() → SQLParserFactory.newInstance() → 具体方言解析器(如MySQLParser) → 词法分析器(Lexer)和语法分析器(Parser) → 语句访问器(StatementVisitor) → 构建Statement对象具体方法调用
SQLParserEngine.parse():主要解析入口
- 入参:sql(SQL字符串)、databaseType(数据库类型)、
parserConfiguration(解析配置) - 返回:解析后的AST节点
- 入参:sql(SQL字符串)、databaseType(数据库类型)、
SQLParserFactory.newInstance():创建解析器实例
- 入参:databaseType(数据库类型)
- 返回:对应方言的解析器工厂
2. 词法分析方法
- SQLLexer:词法分析接口
- 具体实现:如MySQLLexer等方言词法分析器
3. 语法分析方法
- SQLParser:语法分析接口
- 具体实现:如MySQLParser等方言语法分析器
SQL 合法性验证
1. 词法校验
- 处理逻辑:
- 将SQL字符串转换为字符流
- 识别SQL关键字、标识符、操作符、字面量等词法单元
- 验证词法单元的合法性
- 实现方式:基于ANTLR4的词法分析器自动完成
- 异常处理:抛出ParseSQLException等异常
2. 语法校验
- 处理逻辑:
- 构建语法分析器
- 根据SQL语法规则验证语法结构
- 生成抽象语法树(AST)
- 实现方式:基于ANTLR4的语法分析器
- 异常处理:语法错误会抛出相应的解析异常
3. 语义校验
- 处理逻辑:
- 通过访问器模式遍历AST
- 构建结构化的语句对象
- 验证语句的语义正确性
- 实现方式:通过StatementVisitor实现
4. 验证流程示例
// 输入Stringsql="DROP DATABASE IF EXISTS test_db";DatabaseTypedatabaseType=newMySQLDatabaseType();// 调用方法SQLParserEngineparserEngine=newSQLParserEngine();ASTNodeastNode=parserEngine.parse(sql,databaseType,parserConfiguration);// 词法校验:MySQLLexer识别SQL中的词法单元// 语法校验:MySQLParser验证语法结构是否符合MySQL语法// 语义校验:MySQLStatementVisitor构建DropDatabaseStatement对象5. 异常处理机制
- ParseSQLException:解析异常基类
- SQLParsingException:SQL解析异常
- SQLASTVisitorException:AST访问异常
输出对象与输入的对应关系
1. DDL 语句
- 输入:
"DROP DATABASE IF EXISTS test_db" - 输出:DropDatabaseStatement
databaseName= “test_db”ifExists= true
2. DCL 语句
- 输入:
"DROP LOGIN login_name" - 输出:SQLServerDropLoginStatement
loginSegment包含登录名信息
3. 复合结构
- 输入:XML列定义
- 输出:XmlTableColumnSegment
- 包含列名、数据类型、路径等信息
背景:词法解析与语法解析,语义解析
这三者是编译器(或者数据库的 SQL 引擎)处理代码时的三个核心连续阶段。可以把这个过程想象成**“阅读并理解一篇文章”**。
为了让你更清晰地理解,我将通过定义、生活中的比喻以及具体的例子来为你详细拆解。
- 词法解析 (Lexical Analysis) —— “认字”
- 核心任务:把一整段源代码(字符流)拆分成一个个有意义的“单词”或“记号”(Token)。
- 比喻:就像你拿到一本外文书,第一步是认识每一个单词。你不需要知道句子结构,只需要把连续的字母组合成单词,并判断它是名词、动词还是形容词。
- 具体做什么:
- 从左到右扫描字符。
- 识别出关键字(如 SELECT, int)、标识符(变量名/表名)、运算符(+, >)、常量(数字/字符串)等。
- 过滤掉空格、换行符和注释。
- 输入:SELECT name FROM users;
- 输出:一个列表 [KEYWORD(SELECT), ID(name), KEYWORD(FROM), ID(users), OP(😉]
- 语法解析 (Syntax Analysis) —— “分析句子结构”
- 核心任务:拿到词法分析生成的“单词列表”,根据语法规则(文法)检查这些单词的组合顺序是否合法,并构建出一棵“树”。
- 比喻:现在你已经认识所有单词了,接下来要检查句子的语法结构是否正确。比如检查是否符合“主语+谓语+宾语”的结构。它不关心句子的逻辑对不对,只关心“句子长得像不像人话”。
- 具体做什么:
- 验证 Token 序列的结构(例如:检查括号是否匹配、if 语句是否有对应的条件)。
- 构建抽象语法树 (AST),这是一种树状数据结构,表达了代码的层级关系。
- 输入:词法解析生成的 Token 列表。
- 输出:抽象语法树 (AST)。
- 语义解析 (Semantic Analysis) —— “理解句子的含义”
- 核心任务:在语法正确的前提下,检查代码的逻辑和含义是否合法。
- 比喻:现在句子结构完全正确了,但你还要检查它的逻辑通不通。比如句子“颜色睡觉了”在语法上是正确的(主谓结构),但在语义上是荒谬的(颜色不能睡觉)。
- 具体做什么:
- 类型检查:比如不能把字符串赋值给整数类型的变量。
- 变量/函数检查:检查使用的变量或函数是否已经声明,是否有权限访问。
- 表/字段检查:在数据库中,检查 SQL 语句中引用的表名、字段名是否存在。
- 输入:抽象语法树 (AST) 和符号表(包含变量类型、作用域等信息)。
- 输出:带有类型信息和属性的注解 AST,或者报错(如“类型不匹配”、“表不存在”)。
📊 三者对比总结
维度 词法解析 (Lexer) 语法解析 (Parser) 语义解析 (Semantic Analyzer)
关注点单词是什么(微观)结构对不对(中观)逻辑通不通(宏观)
输入字符流 (字符串) Token 序列 抽象语法树 (AST)
输出Token 列表 抽象语法树 (AST) 注解后的 AST / 错误信息
规则依据正则表达式 上下文无关文法 (CFG) 类型系统、符号表
错误示例非法字符、未闭合的引号 缺少分号、括号不匹配 类型不匹配、未声明的变量
🧩 举个完整的例子 (以 SQL 为例)
假设我们有这样一条 SQL 语句:
SELECT name FROM users WHERE age > ‘abc’;
第一阶段:词法解析
系统把它拆成积木块:
- SELECT (关键词)
- name (标识符)
- FROM (关键词)
- users (标识符)
- … …
- age (标识符)
(运算符)
- ‘abc’ (字符串常量)
第二阶段:语法解析
系统检查结构:SELECT 后面跟字段,FROM 后面跟表,WHERE 后面跟条件。结构看起来没问题,于是生成一棵语法树。
第三阶段:语义解析
系统开始深入检查逻辑:
- 表 users 存在吗?
- 字段 name 和 age 在该表中存在吗?
- 关键点:字段 age 通常是整数类型(INT),而 ‘abc’ 是字符串类型(String)。
- 结果:语义解析器会报错:“操作符 > 对应的类型不匹配,整数不能与字符串比较。”
📌 总结
- 词法解析负责切词。
- 语法解析负责组句(构建树)。
- 语义解析负责验意(检查类型、存在性)。
这三个阶段层层递进,只有都通过了,代码才会被编译执行或生成执行计划。