public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            var procedure = ruleExecutionContext.ModelElement;
            var script    = procedure.GetScript();

            var parser = new TSql120Parser(true);
            IList <ParseError> errors = new List <ParseError>();
            var fragment = parser.Parse(new StringReader(script), out errors);

            var visitor = new TransactionVisitor();

            fragment.Accept(visitor);
            var dif = visitor.GetDifference();

            if (dif.Any())
            {
                return
                    new List <SqlRuleProblem>()
                    {
                        new SqlRuleProblem("No balanced transaction", procedure)
                    }
            }
            ;

            return(new List <SqlRuleProblem>());
        }
    }
        /// <summary>
        /// Performs analysis and returns a list of problems detected
        /// </summary>
        /// <param name="ruleExecutionContext">Contains the schema model and model element to analyze</param>
        /// <returns>
        /// The problems detected by the rule in the given element
        /// </returns>
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            List <SqlRuleProblem> problems = new List <SqlRuleProblem>();
            TSqlObject            sqlObj   = ruleExecutionContext.ModelElement;

            if (sqlObj == null || sqlObj.IsWhiteListed())
            {
                return(problems);
            }
            var fragment = ruleExecutionContext.ScriptFragment.GetFragment(typeof(CreateProcedureStatement));
            var name     = sqlObj.Name.GetName();

            var transactionVisitor     = new TransactionVisitor();
            var actionStatementVisitor = new ActionStatementVisitor()
            {
                TypeFilter = ObjectTypeFilter.PermanentOnly
            };

            fragment.Accept(actionStatementVisitor);
            if (actionStatementVisitor.Count <= 1)
            {
                return(problems);
            }
            fragment.Accept(transactionVisitor);
            if (transactionVisitor.Count == 0)
            {
                problems.Add(new SqlRuleProblem(Message, sqlObj));
                return(problems);
            }

            //eliminate rollbacks, and ensure all the action statements are wrapped inside the begin tran...commit tran
            var transactionStatements = transactionVisitor.Statements
                                        .Where(st => st.GetType() == typeof(BeginTransactionStatement) ||
                                               st.GetType() == typeof(CommitTransactionStatement));
            var possibleOffenders = new List <DataModificationStatement>(actionStatementVisitor.Statements);

            for (int i = 0; i < transactionStatements.Count(); i += 2)
            {
                var beginTranLine  = transactionStatements.ElementAt(i).StartLine;
                var commitTranLine = transactionStatements.ElementAt(i + 1).StartLine;

                possibleOffenders.RemoveAll(st => st.StartLine > beginTranLine && st.StartLine < commitTranLine);
            }

            problems.AddRange(possibleOffenders.Select(po => new SqlRuleProblem(Message, sqlObj, po)));

            return(problems);
        }