词法分析器只负责切分token,不识别嵌套结构;语法分析器基于文法规则构建嵌套语法树;预处理器验证嵌套中对象的语义合法性。三者分工明确:词法层切token,语法层建结构,预处理层查元数据。

词法分析器不关心嵌套,只切分 token
MySQL 词法分析器(lex_one_token)本身不识别“嵌套”结构,也不理解子查询、CTE 或括号层级。它只做一件事:从左到右扫描 SQL 字符串,按规则切出一个个 Token,比如 SELECT、(、id、'2023-01-01'、)。哪怕遇到 (SELECT * FROM t WHERE x IN (SELECT y FROM s)) 这种多层括号,它也只负责把每个括号、关键字、标识符、字符串分别打成独立 token,不判断哪对括号属于哪层子查询。
常见错误现象:写成 SELECT * FROM t WHERE id IN (SELECT id FROM u(漏掉右括号),词法分析器不会报错——它能正常切出 SELECT、(、SELECT、FROM 等 token;真正报 ERROR 1064 的是后续的语法分析器,在匹配语法规则时发现括号不闭合。
- 词法分析器跳过所有空白和注释,但会严格区分单引号
'和反引号`:前者进入字符串模式,后者进入标识符模式 - 遇到中文全角符号(如 `=`、`;`)直接报错,因为无法匹配任何预定义 token 规则
-
WITH、OVER、WINDOW等新关键字在 MySQL 8.0+ 才被加入词法表,旧版本会当作非法标识符
嵌套结构靠语法分析器识别和建树
真正处理嵌套逻辑的是语法分析器(MYSQLparse),它基于 sql_yacc.yy 中定义的上下文无关文法(CFG)。比如这条语句:
SELECT a FROM (SELECT b FROM t1) AS s JOIN (SELECT c FROM t2) AS u ON s.b = u.c
语法分析器会按规则递归展开:table_reference → '(' select_stmt ')' → 再次进入 select_stmt 规则,直到整棵树构建完成。它不依赖括号计数,而是靠文法规则推导是否允许某结构出现在某位置。
容易踩的坑:
- MySQL 5.6 不支持
SELECT (SELECT ...)这种无别名的标量子查询,语法分析器直接拒绝;5.7+ 允许,但要求该子查询返回单值 -
WHERE子句里用EXISTS (SELECT ...)是合法的,但若写成WHERE EXISTS SELECT ...(漏括号),语法分析器立刻报错 - CTE 的
WITH必须紧接在第一个SELECT前,中间不能有注释或空行(某些老版本解析器会因状态机切换失败而误判)
括号和引号的嵌套会影响词法状态机切换
词法分析器内部用状态机管理不同解析模式,括号和引号会触发模式切换,这对嵌套 SQL 的 token 切分很关键:
- 遇到
(进入“表达式模式”,此时SELECT仍被识别为关键字;但若在字符串内(如'(SELECT ...)'),它就只是普通字符,不会触发子查询识别 - 反引号
`启动标识符模式,支持嵌套反引号(``a``表示字段名含反引号),但若中间混入未转义的控制字符(如`user\u0000name`),部分 MySQL 版本会截断或报错 - 单引号字符串中双单引号
''表示单引号字符,不是结束符;但若写成'O'Reilly'(没转义),词法分析器会在O'处中断,后续内容被当作文本残留,导致后续 token 错位
预处理器才真正验证嵌套对象的合法性
词法和语法都通过后,预处理器(Preprocessor)才开始检查嵌套结构里的实际对象是否存在:
例如这条语句:
SELECT * FROM (SELECT id, name FROM users) AS u WHERE u.id IN (SELECT user_id FROM orders WHERE status = 'done')
词法分析器切出所有 token,语法分析器确认结构合法,但预处理器要分别查:
- 外层临时表别名
u是否在WHERE中被正确定义(否则报ERROR 1054) - 子查询中的
users表是否存在、id字段是否拼写正确 - 内层子查询的
orders表和status字段是否真实存在且可访问
注意:如果嵌套子查询引用了外层查询的列(相关子查询),预处理器还会做“列可见性”检查——e.salary > (SELECT AVG(salary) FROM employees WHERE dept = e.dept) 中的 e.dept 必须在外层查询范围中声明,否则报错。
真正复杂的地方在于:词法分析器看不到语义,语法分析器只认结构,只有预处理器才把嵌套里的每一层都拉出来查元数据。三者各司其职,缺一不可。











