解析SQL语句时出现NoViableAltException异常的原因及解决方法
使用ANTLR解析MySQL SQL时遇到NoViableAltException的问题排查与解决
环境与配置
- Antlr版本:antlr-4.13.1-complete.jar
- 语法文件:基于MySQL官方ANTLR4语法实现修改,仅新增以下规则处理单字符串多SQL场景:
queryMulti : ((simpleStatement | beginWork) SEMICOLON_SYMBOL?)* EOF ;
- 测试SQL语句:
SELECT * FROM table_a AS a INNER JOIN table_b AS b ON a.field_1=b.field_2
- C#解析代码:
string sql = "SELECT * FROM table_a AS a INNER JOIN table_b AS b ON a.field_1=b.field_2"; ICharStream charStream = CharStreams.fromString(sql); ITokenSource lexer = new MySQLLexer(charStream); ITokenStream stream = new CommonTokenStream(lexer); MySQLParser parser = new MySQLParser(stream); parser.AddErrorListener(new MySQLParserErrorListener()); var treeAll = parser.queryMulti();
异常信息
15:18:48 Error: no viable alternative at input 'SELECT * FROM table_a AS a INNER JOIN table_b AS b ON aS.field_1' - Loc[1(55)] - Antlr4.Runtime.NoViableAltException: Exception of type 'Antlr4.Runtime.NoViableAltException' was thrown. at Antlr4.Runtime.Atn.ParserATNSimulator.ExecATN(DFA dfa, DFAState s0, ITokenStream input, Int32 startIndex, ParserRuleContext outerContext) at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext) at WPF_DbTools.Antlr.MySQLParser.selectStatement() in dir\MySQLParser.cs:line 15862 exception:"Antlr4.Runtime.NoViableAltException"(in Antlr4.Runtime.Standard.dll)
问题分析与解决
1. 异常信息中的'S'并非解析失败原因
这个额外的'S'是ANTLR错误信息的显示bug——它错误拼接了前面AS关键字的最后一个字符与后续标识符a,原SQL实际是AS b ON a.field_1,不存在aS这个输入,只是错误输出时的字符拼接问题。
2. 真正的失败原因与修复方向
- 规则范围不匹配:新增的
queryMulti规则调用了simpleStatement,需确认原MySQL语法中simpleStatement是否包含selectStatement分支。如果原语法中SELECT语句不属于simpleStatement的覆盖范围,解析时就会因找不到匹配规则抛出NoViableAltException。 - 规则逻辑调整:
- 直接改用原语法的顶层语句规则(如
statement)来覆盖所有SQL类型,修改queryMulti规则:queryMulti : (statement SEMICOLON_SYMBOL?)* EOF ; - 若需保留原有分支,补充
selectStatement到可选规则中:queryMulti : ((simpleStatement | selectStatement | beginWork) SEMICOLON_SYMBOL?)* EOF ;
- 直接改用原语法的顶层语句规则(如
- 验证基础规则:先单独调用
parser.selectStatement()解析测试SQL,确认原语法本身能正确处理该语句,再排查queryMulti规则的集成问题。 - 重新生成代码:修改语法文件后,务必重新生成词法、解析器代码,确保规则生效。
内容的提问来源于stack exchange,提问作者hchlqlz
相关产品推荐
相关产品推荐

