/// <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)
        {
            var problems = new List <SqlRuleProblem>();
            var sqlObj   = ruleExecutionContext.ModelElement;

            if (sqlObj == null || sqlObj.IsWhiteListed())
            {
                return(problems);
            }

            var fragment = ruleExecutionContext.ScriptFragment.GetFragment(ProgrammingAndViewSchemaTypes);

            var whereClauseVisitor = new WhereClauseVisitor();

            fragment.Accept(whereClauseVisitor);

            foreach (var whereClause in whereClauseVisitor.Statements)
            {
                var functionVisitor = new FunctionCallVisitor();
                whereClause.Accept(functionVisitor);

                var offenders = from FunctionCall f in functionVisitor.NotIgnoredStatements(RuleId)
                                where CheckFunction(f)
                                select f;

                problems.AddRange(offenders.Select(f => new SqlRuleProblem(Message, sqlObj, f)));
            }

            return(problems);
        }
Example #2
0
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            var problems = new List <SqlRuleProblem>();
            var sqlObj   = ruleExecutionContext.ModelElement;

            if (sqlObj == null || sqlObj.IsWhiteListed())
            {
                return(problems);
            }

            var fragment = ruleExecutionContext.ScriptFragment.GetFragment(ProgrammingSchemaTypes);

            // only visit the function calls inside the where clauses
            var visitor = new WhereClauseVisitor();

            fragment.Accept(visitor);

            foreach (var clause in visitor.Statements)
            {
                var functionVisitor = new FunctionCallVisitor("charindex");
                clause.Accept(functionVisitor);

                problems.AddRange(functionVisitor.NotIgnoredStatements(RuleId).Select(f => new SqlRuleProblem(Message, sqlObj, f)));
            }

            return(problems);
        }
        private bool CheckFunctionCallsForDateFunction(IList <FunctionCall> functionCalls)
        {
            bool hasDateFunctions = false;

            foreach (var functionCall in functionCalls)
            {
                if (FunctionNames.Contains(functionCall.FunctionName.Value.ToLower()))
                {
                    hasDateFunctions = true;
                }
                else
                {
                    foreach (var param in functionCall.Parameters)
                    {
                        var functionVisitor = new FunctionCallVisitor();
                        param.Accept(functionVisitor);
                        hasDateFunctions = hasDateFunctions || CheckFunctionCallsForDateFunction(functionVisitor.Statements);
                        if (hasDateFunctions)
                        {
                            break;
                        }
                    }
                }
                if (hasDateFunctions)
                {
                    break;
                }
            }

            return(hasDateFunctions);
        }
        /// <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)
        {
            var problems = new List <SqlRuleProblem>();
            var sqlObj   = ruleExecutionContext.ModelElement;

            if (sqlObj == null || sqlObj.IsWhiteListed())
            {
                return(problems);
            }

            var fragment = ruleExecutionContext.ScriptFragment.GetFragment(ProgrammingSchemaTypes);

            var ifVisitor = new IfStatementVisitor();

            fragment.Accept(ifVisitor);

            if (ifVisitor.Count == 0)
            {
                return(problems);
            }

            foreach (var ifstmt in ifVisitor.Statements)
            {
                var functionVisitor = new FunctionCallVisitor("count");
                ifstmt.Predicate.Accept(functionVisitor);

                if (functionVisitor.Statements.Any() && CheckIf(ifstmt))
                {
                    problems.Add(new SqlRuleProblem(Message, sqlObj, ifstmt));
                }
            }

            return(problems);
        }
Example #5
0
        private IEnumerable <string> ExtractCalledFunctions(Expression expression)
        {
            var visitor = new FunctionCallVisitor(_knownFunctions.Select(f => f.Name).ToArray());

            visitor.Visit(expression);

            return(visitor.FunctionNames);
        }
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            var problems = new List <SqlRuleProblem>();
            var sqlObj   = ruleExecutionContext.ModelElement;

            if (sqlObj == null || sqlObj.IsWhiteListed())
            {
                return(problems);
            }
            var model    = ruleExecutionContext.SchemaModel;
            var fragment = ruleExecutionContext.ScriptFragment.GetFragment(ProgrammingSchemaTypes);

            var visitor = new DataModificationStatementVisitor();

            fragment.Accept(visitor);

            var modelFunctions = model.GetObjects(DacQueryScopes.UserDefined, new[] { ModelSchema.ScalarFunction, ModelSchema.TableValuedFunction });

            foreach (var stmt in visitor.Statements)
            {
                var functionCallVisitor = new FunctionCallVisitor();
                stmt.Accept(functionCallVisitor);

                foreach (var functionCall in functionCallVisitor.NotIgnoredStatements(RuleId))
                {
                    var createFunctionVisitor = new CreateFunctionVisitor();
                    IList <ParseError> parseErrors;
                    TSqlFragment       fnFragment;

                    var fnName        = functionCall.GetName();
                    var modelFunction = modelFunctions.FirstOrDefault(mf => _comparer.Equals(mf.Name.GetName(), fnName));
                    if (modelFunction == null)
                    {
                        continue;
                    }

                    //we need to parse the sql into a fragment, so we can use the visitors on it
                    fnFragment = modelFunction.GetFragment(out parseErrors);
                    fnFragment.Accept(createFunctionVisitor);

                    if (!createFunctionVisitor.Statements.Any(crfn => crfn.Options != null && crfn.Options.Any(o => o.OptionKind == FunctionOptionKind.SchemaBinding)))
                    {
                        problems.Add(new SqlRuleProblem(Message, sqlObj, functionCall));
                    }
                }
            }


            return(problems);
        }
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            var problems = new List <SqlRuleProblem>();
            var sqlObj   = ruleExecutionContext.ModelElement;

            if (sqlObj == null || sqlObj.IsWhiteListed())
            {
                return(problems);
            }

            var fragment = ruleExecutionContext.ScriptFragment.GetFragment(ProgrammingAndViewSchemaTypes);
            var selectStatementVisitor = new SelectStatementVisitor();

            fragment.Accept(selectStatementVisitor);

            foreach (var statement in selectStatementVisitor.Statements)
            {
                bool found = false;

                if (statement.QueryExpression is QuerySpecification selects)
                {
                    foreach (var selectElement in selects.SelectElements)
                    {
                        var functionCallVisitor = new FunctionCallVisitor();
                        selectElement.Accept(functionCallVisitor);

                        foreach (var function in functionCallVisitor.NotIgnoredStatements(RuleId))
                        {
                            if (function.UniqueRowFilter == UniqueRowFilter.Distinct &&
                                Constants.Aggregates.Contains(function.FunctionName.Value.ToUpper()))
                            {
                                problems.Add(new SqlRuleProblem(Message, sqlObj, statement));
                            }
                        }
                        if (found)
                        {
                            break;
                        }
                    }
                }
            }


            return(problems);
        }
        private bool DoesStatementHaveDateFunction(StatementWithCtesAndXmlNamespaces statement)
        {
            bool hasDateFunction = false;

            var allFunctions = new FunctionCallVisitor();

            statement.Accept(allFunctions);

            if (allFunctions.Statements.Any(p => FunctionNames.Contains(p.FunctionName.Value.ToLower())))
            {
                hasDateFunction = true;
            }
            else
            {
                hasDateFunction = CheckFunctionCallsForDateFunction(allFunctions.Statements);
            }

            return(hasDateFunction);
        }
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            var problems = new List <SqlRuleProblem>();
            var sqlObj   = ruleExecutionContext.ModelElement;

            if (sqlObj == null || sqlObj.IsWhiteListed())
            {
                return(problems);
            }

            var fragment = ruleExecutionContext.ScriptFragment.GetFragment(
                typeof(CreateProcedureStatement),
                typeof(CreateFunctionStatement)
                );

            var variablesVisitor = new VariablesVisitor();

            fragment.Accept(variablesVisitor);
            var variables = variablesVisitor.GetVariables();

            var queries = new QueryStatementVisitor();

            fragment.Accept(queries);

            foreach (var query in queries.Statements)
            {
                var visitor = new FunctionCallVisitor("isnull", "coalesce");
                query.Accept(visitor);

                if (!visitor.Statements.Any())
                {
                    continue;
                }

                var columnDataTypes = new Dictionary <NamedTableView, IDictionary <string, DataTypeView> >();
                query.GetTableColumnDataTypes(columnDataTypes, ruleExecutionContext.SchemaModel);

                foreach (var func in visitor.Statements)
                {
                    var paramTypes = new List <string>();
                    foreach (var parameter in func.Parameters)
                    {
                        if (parameter is ColumnReferenceExpression colRef)
                        {
                            var dtView = columnDataTypes.GetDataTypeView(colRef);
                            if (dtView != null)
                            {
                                paramTypes.Add(dtView.DataType);
                            }
                        }
                        else
                        {
                            paramTypes.Add(GetDataType(parameter, variables));
                        }
                    }
                    if (!paramTypes.All(x => _comparer.Equals(x, paramTypes.First())))
                    {
                        var funcName = func.FunctionName.Value.ToUpper();
                        problems.Add(new SqlRuleProblem(string.Format(Message, funcName), sqlObj, func));
                    }
                }
            }

            return(problems);
        }