微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何分析存储过程以确定是否返回行

如何解决如何分析存储过程以确定是否返回行

给定一个存储过程定义,我可以轻松识别是否存在 SELECT 语句。但是,某些 selects 不会导致返回行。

我正在使用由 herehere 以及 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 举报,一经查实,本站将立刻删除。