.NET 6中TSqlParser校验SQL异常,随机字符串被误判为合法
SQL语法验证误判问题的解决方案
问题场景
你当前使用Microsoft.SqlServer.TransactSql.ScriptDom实现的SQL验证函数,能正确识别"Select From XYZ"这类错误语句为无效SQL,但会把"sdcsdcsdcsdcsjnjkc"、"csdcsdc sdcsdcsdc"这类随机字符串判定为合法SQL,需要修正这个误判问题。
你的现有实现代码:
using Microsoft.SqlServer.TransactSql.ScriptDom; using ParseError = Microsoft.SqlServer.TransactSql.ScriptDom.ParseError; namespace QueryStore.Application.Utils; internal static class SqlParser { internal static List<string>? Parse(string sql) { var parser = new TSql100Parser(false); parser.Parse(new StringReader(sql), out IList<ParseError> errors); return errors is not { Count: > 0 } ? null : errors.Select(error => error.Message).ToList(); } internal static bool BeValidSqlQuery(string content) { var result = SqlParser.Parse(content); return result is null; } }
一、修正现有TSqlParser的验证逻辑
TSql100Parser默认会把孤立的标识符或标识符组合当作合法的批处理语句(比如单独的变量名、存储过程名),所以需要额外校验解析后的语法树是否包含有效的查询语句(如SELECT/INSERT/UPDATE/DELETE等)。
修改后的代码示例:
using Microsoft.SqlServer.TransactSql.ScriptDom; using ParseError = Microsoft.SqlServer.TransactSql.ScriptDom.ParseError; using System.IO; using System.Linq; namespace QueryStore.Application.Utils; internal static class SqlParser { internal static List<string>? Parse(string sql) { var parser = new TSql100Parser(false); using var reader = new StringReader(sql); var fragment = parser.Parse(reader, out IList<ParseError> errors); // 先检查语法错误 if (errors.Any()) { return errors.Select(error => error.Message).ToList(); } // 再检查是否包含有效的查询语句节点 var hasValidQuery = CheckForValidQuery(fragment); return hasValidQuery ? null : new List<string> { "输入不是有效的SQL查询语句" }; } internal static bool BeValidSqlQuery(string content) { var result = SqlParser.Parse(content); return result is null; } private static bool CheckForValidQuery(TSqlFragment fragment) { var visitor = new QueryStatementVisitor(); fragment.Accept(visitor); return visitor.HasValidQuery; } // 自定义语法树访问器,过滤出有效的查询语句类型 private class QueryStatementVisitor : TSqlFragmentVisitor { public bool HasValidQuery { get; private set; } public override void Visit(SelectStatement node) => HasValidQuery = true; public override void Visit(InsertStatement node) => HasValidQuery = true; public override void Visit(UpdateStatement node) => HasValidQuery = true; public override void Visit(DeleteStatement node) => HasValidQuery = true; public override void Visit(MergeStatement node) => HasValidQuery = true; // 可根据业务需求添加其他需要验证的语句类型,如ExecuteStatement、CreateTableStatement等 } }
二、其他可选的SQL验证方案
如果不想基于TSqlParser扩展,也可以考虑以下库:
- Dapper.SqlParser:轻量型SQL解析库,专注于查询语句的合法性校验,对随机字符串这类无效输入的识别更严格
- ANTLR4 TSQL语法库:基于ANTLR4生成的TSQL语法解析器,可通过自定义语法规则精准过滤无效的孤立标识符
关键说明
TSqlParser的设计目标是解析合法的TSQL批处理语句,而非专门验证“完整可执行的查询语句”,所以孤立标识符会被视为合法批处理(比如单独的变量名@var或存储过程名sp_help)。通过自定义语法树访问器,可以精准控制需要验证的SQL语句类型,彻底避免随机字符串的误判问题。
内容的提问来源于stack exchange,提问作者Hardik Dhuri
相关产品推荐
相关产品推荐

