如何解决如何分析存储过程以确定是否返回行
给定一个存储过程定义,我可以轻松识别是否存在 SELECT
语句。但是,某些 selects
不会导致返回行。
我正在使用由 here 和 here 以及 CaseChangingCharstream.cs 提供的 ANTLR4 语法文件。 (我发现我需要将第 71 和 73 行 LA
更改为 La
)
到目前为止,我一直无法确定我应该在用例中使用的正确侦听器覆盖(EnterSelect_that_returns_rows()
太简单了 :))
以下测试说明了问题。
private TsqlParser GetParser(string sql)
{
AntlrInputStream input = new AntlrInputStream(sql);
CaseChangingCharStream upperCase = new CaseChangingCharStream(input,true);
TsqlLexer lexer = new TsqlLexer(upperCase);
CommonTokenStream tokens = new CommonTokenStream(lexer);
return new TsqlParser(tokens);
}
[TestMethod]
public void TestProcedureWithSelect()
{
TsqlParser parser = GetParser("CREATE PROCEDURE TestProc BEGIN print 'Testing'; SELECT 'Hello World'; END;");
TestListener listener = new TestListener();
ParseTreeWalker walker = new ParseTreeWalker();
bool built = parser.BuildParseTree;
walker.Walk(listener,parser.tsql_file());
Assert.IsTrue(listener.ReturnsRows); // Passes but 'so what'
}
[TestMethod]
public void TestProcedureWithSelectparam()
{
TsqlParser parser = GetParser("CREATE PROCEDURE TestProc BEGIN DECLARE @var nvarchar(256); print 'Testing'; SELECT @var = 'Hello World'; END;");
TestListener listener = new TestListener();
ParseTreeWalker walker = new ParseTreeWalker();
bool built = parser.BuildParseTree;
walker.Walk(listener,parser.tsql_file());
Assert.IsFalse(listener.ReturnsRows); // Pass,but probably a kludge
}
[TestMethod]
public void TestInsertInto()
{
TsqlParser parser = GetParser("CREATE PROCEDURE TestProc BEGIN DECLARE @var nvarchar(256); print 'Testing'; INSERT INTO TABLE (FIELD) SELECT 'Hello World'; END;");
TestListener listener = new TestListener();
ParseTreeWalker walker = new ParseTreeWalker();
bool built = parser.BuildParseTree;
walker.Walk(listener,parser.tsql_file());
Assert.IsFalse(listener.ReturnsRows); //Fails (I have no solution for this)
}
}
我目前的样子是这样的
using Antlr4.Runtime.Misc;
using ANTLRTsqlParser.Grammar;
namespace ParserTests
{
public class TestListener : TsqlParserBaseListener
{
public bool ReturnsRows = false;
public override void EnterSelect_list([NotNull] TsqlParser.Select_listContext context)
{
var elements = context.select_list_elem();
if(!elements[0].GetText().Contains("="))
ReturnsRows = true;
}
}
}
我现在已将以下内容添加到我的听众中。我想知道是否有人可以评论以这种方式使用标志的智慧
private bool inDML = false;
public override void EnterDml_clause([NotNull] TsqlParser.Dml_clauseContext context)
{
inDML = true;
}
public override void ExitDml_clause([NotNull] TsqlParser.Dml_clauseContext context)
{
inDML = false;
}
public override void EnterSelect_statement([NotNull] TsqlParser.Select_statementContext context)
{
ReturnsRows = !inDML;
}
我已经决定了
private Stack<bool> nonRowReturningStatements = new Stack<bool>();
public override void EnterDml_clause([NotNull] TsqlParser.Dml_clauseContext context) { nonRowReturningStatements.Push(true); }
public override void ExitDml_clause([NotNull] TsqlParser.Dml_clauseContext context) { nonRowReturningStatements.Pop(); }
public override void EnterDeclare_statement([NotNull] TsqlParser.Declare_statementContext context) { nonRowReturningStatements.Push(true); }
public override void ExitDeclare_statement([NotNull] TsqlParser.Declare_statementContext context) { nonRowReturningStatements.Pop(); }
public override void EnterDeclare_cursor([NotNull] TsqlParser.Declare_cursorContext context) { nonRowReturningStatements.Push(true); }
public override void ExitDeclare_cursor([NotNull] TsqlParser.Declare_cursorContext context) { nonRowReturningStatements.Pop(); }
public override void EnterSet_statement([NotNull] TsqlParser.Set_statementContext context) { nonRowReturningStatements.Push(true); }
public override void ExitSet_statement([NotNull] TsqlParser.Set_statementContext context) { nonRowReturningStatements.Pop(); }
public override void EnterSelect_statement([NotNull] TsqlParser.Select_statementContext context)
{
if (!FuncProc.ReturnsRows && nonRowReturningStatements.Count == 0)
{
FuncProc.ReturnsRows = !context.query_expression()
.query_specification()
.select_list()
.select_list_elem()[0]
.GetText()
.Contains("=");
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。