类 Parser 只有 Parse 方法返回 ParseResult ,似乎我无法对 ParseResult <做什么/ strong>即可。 如何获取我的sql语句的抽象语法树,或者只是从sql解析元数据标记就可以了。
答案 0 :(得分:4)
我做了一些研究,发现我可以使用反射来生成使用 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();
答案 1 :(得分:1)
我很兴奋你发现了AST!直接使用它需要使用动态变量来访问内部--
命名空间中对象的.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;
)。
// 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>();
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);
}
}
如果您真的愿意仅仅考虑元数据令牌,我找到了一个PowerShell示例here;它可以解决这个问题(为了完整性而包含样板元数据工厂):
$arrayOfIds = array('A0000-000000000001','B0000-000000000001','C0000-000000000001');
$status = 1;
$sql = "SELECT name FROM my_table WHERE status = ? AND id IN ?";
$query = $this->db->query($sql, array($status, $arrayOfIds));