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 visitor  = new JoinVisitor();

            fragment.Accept(visitor);
            var views = sqlObj.GetReferenced(DacQueryScopes.UserDefined)
                        .Where(x => x.ObjectType == ModelSchema.View).Select(v => v.Name.Parts.Last()).ToList();

            var joins = visitor.QualifiedJoins.Where(j => Ignorables.ShouldNotIgnoreRule(j.ScriptTokenStream, RuleId, j.StartLine));

            var leftSideOffenders =
                from o in joins
                where o.FirstTableReference != null &&
                views.Contains((o.FirstTableReference as NamedTableReference)?.SchemaObject.Identifiers.Last().Value)
                select o.FirstTableReference as NamedTableReference;

            var rightSideOffenders =
                from o in joins
                where o.SecondTableReference != null &&
                views.Contains((o.SecondTableReference as NamedTableReference)?.SchemaObject.Identifiers.Last().Value)
                select o.SecondTableReference as NamedTableReference;

            problems.AddRange(leftSideOffenders.Union(rightSideOffenders).Select(o => new SqlRuleProblem(Message, sqlObj, o)));

            return(problems);
        }
 protected override Expression VisitMethodCall(MethodCallExpression node)
 {
     if (node.Method.Name == nameof(Enumerable.Where))
     {
         var        predicate   = node.Arguments[1] is UnaryExpression quote ? (LambdaExpression)quote.Operand : (LambdaExpression)node.Arguments[1];
         var        joinVisitor = new JoinVisitor(_edmModel, node.Arguments[0], predicate.Parameters[0]);
         Expression expression  = joinVisitor.Visit(node.Arguments[1]);
         if (node.Arguments[1] != expression)
         {
             Expression[] arguments = node.Arguments.ToArray();
             arguments[1] = expression;
             return(node.Update(node.Object !, arguments));
         }
     }
     else if (node.Method.Name == nameof(Enumerable.SelectMany) && node.Arguments.Count == 2)
     {
         var        predicate   = node.Arguments[1] is UnaryExpression quote ? (LambdaExpression)quote.Operand : (LambdaExpression)node.Arguments[1];
         var        joinVisitor = new JoinVisitor(_edmModel, node.Arguments[0], predicate.Parameters[0]);
         Expression body        = joinVisitor.Visit(predicate.Body);
         if (predicate.Body != body)
         {
             Expression[] arguments = node.Arguments.ToArray();
             arguments[1] = Expression.Lambda(body, predicate.Parameters);
             return(node.Update(node.Object !, arguments));
         }
     }
     return(base.VisitMethodCall(node));
 }
    public static IEnumerable <Type> GetJoinTypes(System.Linq.Expressions.Expression expression)
    {
        var joinVisitor = new JoinVisitor();

        joinVisitor.Visit(expression);
        return(joinVisitor.Types);
    }
示例#4
0
        /// <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 tableHintVisitor = new TableHintVisitor();
            var queryHintVisitor = new StatementListVisitor();
            var joinHintVisitor  = new JoinVisitor();

            fragment.Accept(tableHintVisitor, queryHintVisitor, joinHintVisitor);

            var tableOffenders =
                from n in tableHintVisitor.NotIgnoredStatements(RuleId)
                where n.HintKind != TableHintKind.NoLock
                select n;

            var queryOffenders =
                from o in queryHintVisitor.NotIgnoredStatements(RuleId)
                from o1 in o.Statements
                let s = o1 as StatementWithCtesAndXmlNamespaces
                        where s?.OptimizerHints != null && s?.OptimizerHints.Count > 0
                        select s;

            var joinOffenders =
                from j in joinHintVisitor.NotIgnoredStatements(RuleId)
                where j is QualifiedJoin &&
                ((QualifiedJoin)j).JoinHint != JoinHint.None
                select j as QualifiedJoin;

            problems.AddRange(tableOffenders.Select(o => new SqlRuleProblem(Message, sqlObj, o)));
            problems.AddRange(queryOffenders.Select(o => new SqlRuleProblem(Message, sqlObj, o)));
            problems.AddRange(joinOffenders.Select(o => new SqlRuleProblem(Message, sqlObj, o)));

            return(problems);
        }
        /// <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 joinVisitor = new JoinVisitor();

            fragment.Accept(joinVisitor);

            foreach (var join in joinVisitor.Statements)
            {
                var tableVarVisitor = new TableVariableVisitor();
                join.Accept(tableVarVisitor);

                problems.AddRange(tableVarVisitor.NotIgnoredStatements(RuleId).Select(tv => new SqlRuleProblem(Message, sqlObj, tv)));
            }
            return(problems);
        }
示例#6
0
        public static IList <JoinInfo> GetFromClauseJoinTables(this FromClause from)
        {
            if (from == null)
            {
                throw new ArgumentNullException(nameof(from));
            }
            var joins = new List <JoinInfo>();

            if (from.TableReferences.Count == 0 || from.TableReferences.First().GetType() != typeof(QualifiedJoin))
            {
                return(joins);
            }

            var joinVisitor = new JoinVisitor();

            from.Accept(joinVisitor);

            //build the list of pure tables along with the list of boolean comparisons
            foreach (var join in joinVisitor.QualifiedJoins)
            {
                var joinInfo = new JoinInfo {
                };

                var boolVisitor = new BooleanComparisonVisitor();
                join.SearchCondition.Accept(boolVisitor);
                joinInfo.Compares = new List <BooleanComparisonExpression>(boolVisitor.Statements);

                if (join.FirstTableReference.GetType() == typeof(NamedTableReference))
                {
                    joinInfo.Table1 = join.FirstTableReference as NamedTableReference;
                }
                if (join.SecondTableReference.GetType() == typeof(NamedTableReference))
                {
                    joinInfo.Table2 = join.SecondTableReference as NamedTableReference;
                }
                joins.Add(joinInfo);
            }

            //table2 should always have a table..... maybe. unless the table is actually a sub-select. Then we will ignore it
            foreach (var join in joins.Where(j => j.Table2 != null))
            {
                var table1      = join.Table1;
                var table2      = join.Table2;
                var table2Alias = table2.Alias?.Value;
                var table2Name  = new ObjectIdentifier(table2.SchemaObject.Identifiers.Select(x => x.Value));

                //we need to figure out which side of the comparison goes to which table..... PITA. yes.....
                foreach (var compare in join.Compares
                         .Where(x => x.FirstExpression is ColumnReferenceExpression && x.SecondExpression is ColumnReferenceExpression))
                {
                    //we use a loop as we need to check both the first expression and the second expression to see which table the columns belong to
                    for (int i = 0; i < 2; i++)
                    {
                        var col        = (i == 0 ? compare.FirstExpression : compare.SecondExpression) as ColumnReferenceExpression;
                        var colTblName = GetTableOrAliasName(col.MultiPartIdentifier.Identifiers);
                        if (table2Alias.StringEquals(colTblName.First()) || table2Name.CompareTo(colTblName) >= 5)
                        {
                            join.Table2JoinColumns.Add(col);
                            continue;
                        }

                        //use table1 if it was supplied in the compare. else scan the joins to find the matching table to the column
                        var tbl = table1 ?? joins.Select(x =>
                        {
                            if (CheckName(x.Table2, col))
                            {
                                return(x.Table2);
                            }
                            if (CheckName(x.Table1, col))
                            {
                                return(x.Table1);
                            }
                            return(null);
                        }).FirstOrDefault(x => x != null);

                        if (tbl != null)
                        {
                            var tblAlias = tbl.Alias?.Value;
                            var tblName  = new ObjectIdentifier(tbl.SchemaObject.Identifiers.Select(x => x.Value));

                            if (join.Table1 == null)
                            {
                                join.Table1 = tbl;
                            }
                            if (tblAlias.StringEquals(colTblName.First()) || tblName.CompareTo(colTblName) >= 5)
                            {
                                join.Table1JoinColumns.Add(col);
                            }
                        }
                    }
                }
            }

            return(joins);
        }
示例#7
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(ProgrammingAndViewSchemaTypes);
            var visitor  = new SelectStatementVisitor();

            fragment.Accept(visitor);

            foreach (var stmt in visitor.Statements)
            {
                var querySpecificationVisitor = new QuerySpecificationVisitor();
                stmt.QueryExpression.Accept(querySpecificationVisitor);

                foreach (var query in querySpecificationVisitor.Statements)
                {
                    var fromClause = query.FromClause;
                    if (fromClause == null)
                    {
                        continue;
                    }
                    var joinVisitor = new JoinVisitor();
                    fromClause.Accept(joinVisitor);

                    var outerJoins =
                        (from j in joinVisitor.QualifiedJoins
                         let t = j.QualifiedJoinType
                                 where (t == QualifiedJoinType.LeftOuter || t == QualifiedJoinType.RightOuter) &&
                                 Ignorables.ShouldNotIgnoreRule(j.ScriptTokenStream, RuleId, j.StartLine)
                                 select j).ToList();

                    if (outerJoins.Count == 0)
                    {
                        continue;
                    }
                    var columns = ColumnReferenceExpressionVisitor.VisitSelectElements(query.SelectElements);

                    var whereClause = query.WhereClause;
                    if (whereClause == null)
                    {
                        continue;
                    }
                    var isnullVisitor = new ISNULLVisitor();
                    whereClause.Accept(isnullVisitor);
                    if (isnullVisitor.Count == 0)
                    {
                        continue;
                    }

                    foreach (var join in outerJoins)
                    {
                        TableReference table = null;
                        if (join.QualifiedJoinType == QualifiedJoinType.LeftOuter)
                        {
                            table = join.SecondTableReference as TableReference;
                        }
                        else
                        {
                            table = join.FirstTableReference as TableReference;
                        }

                        var tableName = table.GetName();
                        var alias     = (table as TableReferenceWithAlias)?.Alias.Value;

                        //are there any columns in the select that match this table?
                        if (columns.Any(c =>
                        {
                            var colTableName = c.GetName();
                            return(_comparer.Equals(tableName, colTableName) || _comparer.Equals(alias, colTableName));
                        }))
                        {
                            continue;
                        }

                        //no columns, now we need to look in the where clause for a null check againt this table.
                        if (isnullVisitor.Statements.Any(nc =>
                        {
                            var col = nc.FirstExpression as ColumnReferenceExpression ?? nc.SecondExpression as ColumnReferenceExpression;
                            if (col == null)
                            {
                                return(false);
                            }
                            var colTableName = col.GetName();
                            return(_comparer.Equals(tableName, colTableName) || _comparer.Equals(alias, colTableName));
                        }))
                        {
                            problems.Add(new SqlRuleProblem(Message, sqlObj, join));
                        }
                    }
                }
            }

            return(problems);
        }