如何使用Microsoft.SqlServer.Management.SqlParser中的类将T-SQL解析为AST

Parser只有Parse返回ParseResult的方法,而且我似乎无法对ParseResult做任何事情 。 如何获取我的sql语句的抽象语法树,或者只是从sql解析元数据标记就可以了。

我做了一些研究,发现我可以使用reflection来生成使用SqlScript.WriteXml解析的信息xml文件。 这里是示例代码,我不知道是否有更好的方法。

var rst = Parser.Parse(File.ReadAllText(@"*.sql")); var fieldInfo = rst.GetType().GetField("sqlScript", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField); var script = fieldInfo.GetValue(rst); var writer = XmlWriter.Create("*.xml"); script.GetType().InvokeMember("WriteXml", BindingFlags.NonPublic| BindingFlags.Instance | BindingFlags.InvokeMethod , null, script, new object[] { writer }); writer.Close(); 

我很兴奋你发现了AST! 直接使用它需要使用动态变量来访问内部Microsoft.SqlServer.Management.SqlParser.SqlCodeDom命名空间中的对象的.Child集合。

我建议访问现有的Xml字符串属性,而不是调用WriteXml。 这节省了必须处理在XML注释中嵌套SQL注释所导致的问题(不能--在XML注释中; --变成- - )。

 var rst = Parser.Parse(File.ReadAllText(@"*.sql")); var script = rst.GetType().GetProperty("Script", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(rst); var xml = script.GetType().BaseType.GetProperty("Xml").GetValue(script) as String; 

如果你真的愿意只接受元数据令牌,我在这里找到了一个PowerShell示例; 它可以解决这个问题(为了完整性而包含样板元数据工厂):

 // using Microsoft.SqlServer.Management.SqlParser.Parser; // ... var sql = File.ReadAllText(@"*.sql"); var scanner = new Scanner(new ParseOptions()); int scannerState = 0; scanner.SetSource(sql, 0); var allTokens = new List(); MSSQL_Token_JS curToken = null; do { curToken = MSSQL_Token_JS.GetNext(scanner, sql, ref scannerState); allTokens.Add(curToken); } while (curToken.Value != Tokens.EOF); //... public class MSSQL_Token_JS { public readonly string SourceSQL; public readonly Tokens Value; public readonly string Text; public readonly int ScannerState; public readonly int Start; public readonly int End; public readonly bool IsPairMatch; public readonly bool IsExecAutoParamHelp; private MSSQL_Token_JS(string SourceSQL, int tokenId, int ScannerState, int Start, int End, bool IsPairMatch, bool IsExecAutoParamHelp) { this.SourceSQL = SourceSQL; this.Value = (Tokens)tokenId; if (this.Value != Tokens.EOF) { this.Text = SourceSQL.Substring(Start, End - Start + 1); } this.ScannerState = ScannerState; this.Start = Start; this.End = End; this.IsPairMatch = IsPairMatch; this.IsExecAutoParamHelp = IsExecAutoParamHelp; } public static MSSQL_Token_JS GetNext(Scanner scanner, string SourceSQL, ref int ScannerState) { int start, end; bool isPairMatch, isExecAutoParamHelp; int tokenId = scanner.GetNext(ref ScannerState, out start, out end, out isPairMatch, out isExecAutoParamHelp); return new MSSQL_Token_JS(SourceSQL, tokenId, ScannerState, start, end, isPairMatch, isExecAutoParamHelp); } public override string ToString() { return String.Format("{0}:{1}", this.Value, this.Text); } }