예제 #1
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);
            var visitor  = new RaiseErrorVisitor();

            fragment.Accept(visitor);

            var offenders =
                from r in visitor.Statements
                where
                r.SecondParameter is IntegerLiteral &&
                int.Parse((r.SecondParameter as Literal)?.Value) > 18 &&
                (r.RaiseErrorOptions & RaiseErrorOptions.Log) != RaiseErrorOptions.Log
                select r;

            problems.AddRange(offenders.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 sqlObjName = ruleExecutionContext.GetObjectName(sqlObj);
            var fragment   = ruleExecutionContext.ScriptFragment.GetFragment(ProgrammingAndViewSchemaTypes);

            var whereClauseVisitor = new WhereClauseVisitor();

            fragment.Accept(whereClauseVisitor);

            foreach (var whereClause in whereClauseVisitor.Statements)
            {
                var inPredicateVisitor = new InPredicateVisitor();
                whereClause.Accept(inPredicateVisitor);

                var offenders = inPredicateVisitor.NotIgnoredStatements(RuleId).Where(i => i.Subquery != null);
                problems.AddRange(offenders.Select(t => new SqlRuleProblem(Message, sqlObj, t)));
            }

            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(ProgrammingAndViewSchemaTypes);

            // only visit the operators in the where clause
            var visitor = new WhereClauseVisitor();

            fragment.Accept(visitor);

            foreach (var clause in visitor.Statements)
            {
                var beVisitor = new BooleanParenthesesExpressionVisitor();
                clause.Accept(beVisitor);

                var offenders = (from BooleanParenthesisExpression be in beVisitor.NotIgnoredStatements(RuleId)
                                 where TestClause(be)
                                 select be).ToList();

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

            return(problems);
        }
        private void AnalyzeJoins(IList <SqlRuleProblem> problems, SqlRuleExecutionContext ruleExecutionContext,
                                  QuerySpecification querySpecification)
        {
            var visitor = new CollectJoinVisitor();

            querySpecification.Accept(visitor);
            foreach (var join in visitor.Joins)
            {
                // We should have already handled the first table reference here, as it's included from an earlier part
                // of the query. As such, we now handle the second table only.
                var tablePartitions = CollectFromTableReference(ruleExecutionContext, join.SecondTableReference,
                                                                join.SecondTableReference).ToList();

                if (tablePartitions.Count == 0)
                {
                    continue;
                }

                if (join is QualifiedJoin qualifiedJoin)
                {
                    var condition = qualifiedJoin.SearchCondition;
                    SearchConstraints(condition, tablePartitions);
                }

                foreach (var partitionedColumn in tablePartitions)
                {
                    SqlRuleProblem problem = CreateProblem(ruleExecutionContext, partitionedColumn);
                    problems.Add(problem);
                }
            }
        }
        private IEnumerable <PartitionedColumn> CollectFromTableReference(SqlRuleExecutionContext ruleExecutionContext,
                                                                          TSqlFragment fragment, TableReference tableReference)
        {
            if (!(tableReference is NamedTableReference namedTableReference))
            {
                return(new List <PartitionedColumn>());
            }

            // Resolve the table from its name.
            var table =
                ResolveTable(ruleExecutionContext.SchemaModel, namedTableReference.SchemaObject);

            if (table == null)
            {
                return(new List <PartitionedColumn>());
            }
            // In the tabe object, find all columns that are a partition column, and save them.
            var partitionColumns = table.GetReferenced(Table.PartitionColumn, DacQueryScopes.All);

            var allowedTableNames = new HashSet <string>();

            allowedTableNames.Add(namedTableReference.SchemaObject.BaseIdentifier.Value);
            if (namedTableReference.Alias != null)
            {
                allowedTableNames.Add(namedTableReference.Alias.Value);
            }

            return(partitionColumns
                   .Select(x => new PartitionedColumn(
                               allowedTableNames,
                               x.Name.Parts.Last(), fragment)));
        }
예제 #6
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(ProgrammingSchemaTypes);

            if (fragment.ScriptTokenStream == null)
            {
                return(problems);
            }
            var visitor = new DeclareVariableElementVisitor();

            fragment.Accept(visitor);

            var vars = from pp in visitor.Statements
                       join t in fragment.ScriptTokenStream
                       on new { Name = pp.VariableName.Value?.ToLower(), Type = TSqlTokenType.Variable }
            equals new { Name = t.Text?.ToLower(), Type = t.TokenType }
            select pp;

            var unusedVars = vars.GroupBy(p => p.VariableName.Value?.ToLower()).Where(g => g.Count() == 1).Select(g => g.First());

            problems.AddRange(unusedVars.Select(v => new SqlRuleProblem(string.Format(Message, v.VariableName.Value), sqlObj, v)));

            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(
                typeof(CreateProcedureStatement),
                typeof(CreateTriggerStatement));
            var visitor = new PredicateVisitor();

            fragment.Accept(visitor);

            var predicates = from o
                             in visitor.Statements
                             where o.Options == SetOptions.NoCount && o.IsOn
                             select o;

            var createToken = fragment.ScriptTokenStream.FirstOrDefault(t => t.TokenType == TSqlTokenType.Create);

            if (!predicates.Any() && Ignorables.ShouldNotIgnoreRule(fragment.ScriptTokenStream, RuleId, createToken.Line))
            {
                problems.Add(new SqlRuleProblem(Message, sqlObj));
            }
            return(problems);
        }
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext context)
        {
            IList <SqlRuleProblem> problems = new List <SqlRuleProblem>();
            TSqlObject             index    = context.ModelElement;

            if (!IsIndexOnMemoryOptimizedTable(index))
            {
                // Only examining memory optimized tables, anything else can be ignored
                // Note the call to the Table.MemoryOptimized property: this is where we verify the in-memory behavior
                return(problems);
            }

            TSqlObject databaseOptions = context.SchemaModel
                                         .GetObjects(DacQueryScopes.UserDefined, DatabaseOptions.TypeClass).SingleOrDefault();

            if (databaseOptions == null)
            {
                // This should never happen as the database options are automatically created
                return(problems);
            }

            string defaultCollation = databaseOptions.GetProperty <string>(DatabaseOptions.Collation);

            AnalyzeColumns(context, index, defaultCollation, problems);

            return(problems);
        }
예제 #9
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)
        {
            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 visitor = new InsertStatementVisitor();

            fragment.Accept(visitor);
            if (visitor.Count == 0)
            {
                return(problems);
            }

            var offenders = visitor.Statements.Where(s => s.InsertSpecification.Columns.Count == 0).ToList();

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

            return(problems);
        }
예제 #10
0
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            IList <SqlRuleProblem> problems = new List <SqlRuleProblem>();

            TSqlObject modelElement = ruleExecutionContext.ModelElement;

            if (IsInlineTableValuedFunction(modelElement))
            {
                return(problems);
            }

            string elementName = GetElementName(ruleExecutionContext, modelElement);

            TSqlFragment        fragment       = ruleExecutionContext.ScriptFragment;
            RuleDescriptor      ruleDescriptor = ruleExecutionContext.RuleDescriptor;
            WaitForDelayVisitor visitor        = new WaitForDelayVisitor();

            fragment.Accept(visitor);

            IList <WaitForStatement> waitForDelayStatements = visitor.WaitForDelayStatements;

            foreach (WaitForStatement waitForStatement in waitForDelayStatements)
            {
                var problem = new SqlRuleProblem(string.Format(CultureInfo.CurrentCulture, ruleDescriptor.DisplayDescription, elementName), modelElement, waitForStatement);
                problems.Add(problem);
            }

            return(problems);
        }
        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)
        {
            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);
        }
        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 openCursorVisitor = new OpenCursorVisitor();

            fragment.Accept(openCursorVisitor);

            if (openCursorVisitor.Count > 0)
            {
                var deallocateCursorVisitor = new DeallocateCursorVisitor();
                fragment.Accept(deallocateCursorVisitor);

                var localOpenCursors       = openCursorVisitor.Statements.Where(c => !c.Cursor.IsGlobal);
                var localDeallocateCursors = deallocateCursorVisitor.Statements.Where(c => !c.Cursor.IsGlobal);

                var unDeallocatedCursors = localOpenCursors.Where(c =>
                                                                  !localDeallocateCursors.Any(c2 => _comparer.Equals(c.Cursor.Name.Value, c2.Cursor.Name.Value)));

                foreach (var cursor in unDeallocatedCursors)
                {
                    problems.Add(new SqlRuleProblem(Message, sqlObj, cursor));
                }
            }

            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(typeof(CreateProcedureStatement));

            var typesVisitor = new TypesVisitor(
                typeof(SelectStatement),
                typeof(UpdateStatement),
                typeof(DeleteStatement),
                typeof(InsertStatement),
                typeof(CreateTableStatement)
                );

            fragment.Accept(typesVisitor);

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

            var offenders = typesVisitor.Statements
                            .SkipWhile(t => t.GetType() == typeof(CreateTableStatement))
                            .Where(t1 => t1.GetType() == typeof(CreateTableStatement));

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

            return(problems);
        }
예제 #15
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(ProgrammingSchemaTypes);
            var visitor  = new OrderByVisitor();

            fragment.Accept(visitor);

            var offenders = (from o in visitor.NotIgnoredStatements(RuleId)
                             from e in o.OrderByElements
                             where e.Expression is IntegerLiteral
                             select e).Distinct();

            foreach (var offender in offenders)
            {
                problems.Add(new SqlRuleProblem(Message, sqlObj, offender));
            }

            return(problems);
        }
예제 #16
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);
        }
        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));
            var objName  = sqlObj.Name.GetName();

            var grantVisitor = new GrantVisitor();

            fragment.Accept(grantVisitor);

            if (grantVisitor.Statements
                .Any(g => g.SecurityTargetObject.ObjectName.MultiPartIdentifier.CompareTo(sqlObj.Name) >= 5))
            {
                problems.Add(new SqlRuleProblem(Message, sqlObj));
            }

            return(problems);
        }
예제 #18
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(ProgrammingSchemaTypes);
            var visitor  = new SelectStatementVisitor();

            fragment.Accept(visitor);

            var offenders =
                from s in visitor.NotIgnoredStatements(RuleId)
                let tn = s.Into == null ? "" : s.Into.Identifiers?.LastOrDefault()?.Value
                         where s.Into != null && !(tn.StartsWith("#") || !tn.StartsWith("@"))
                         select s.Into;

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

            return(problems);
        }
        private static void AnalyzeColumns(
            SqlRuleExecutionContext context,
            TSqlObject index,
            string defaultCollation,
            IList <SqlRuleProblem> problems)
        {
            foreach (TSqlObject column in index.GetReferenced(Index.Columns)
                     .Where(column => IsCharacterColumn(column)))
            {
                // Fall back on the default project collation if none is defined for the specific column
                string collation = column.GetProperty <string>(Column.Collation) ?? defaultCollation ?? string.Empty;
                if (!collation.EndsWith(Bin2Ending, StringComparison.OrdinalIgnoreCase))
                {
                    // Error looks liks "Index <name> on column <name> should have a BIN2 collation instead of <collation>"
                    // Choosing to add 1 problem per-column. This will cause more warnings in the error manager but is more precise
                    string errorMsg = string.Format(CultureInfo.CurrentCulture,
                                                    context.RuleDescriptor.DisplayDescription,
                                                    RuleUtils.GetElementName(index, context, ElementNameStyle.EscapedFullyQualifiedName),
                                                    RuleUtils.GetElementName(column, context, ElementNameStyle.EscapedFullyQualifiedName),
                                                    collation);

                    SqlRuleProblem problem = new SqlRuleProblem(errorMsg, index);
                    problems.Add(problem);
                }
            }
        }
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            IList <SqlRuleProblem> problems = new List <SqlRuleProblem>();

            var modelElement = ruleExecutionContext.ModelElement;

            var displayServices = ruleExecutionContext.SchemaModel.DisplayServices;

            var objectName = displayServices.GetElementName(ruleExecutionContext.ModelElement,
                                                            ElementNameStyle.FullyQualifiedName);

            var fragment = ruleExecutionContext.ScriptFragment;

            var visitor = new ParameterVisitor();

            fragment.Accept(visitor);

            foreach (var element in visitor.DeclareVariableElements)
            {
                var problemDescription = string.Format(Message, element.VariableName.Value, objectName);

                var problem = new SqlRuleProblem(problemDescription, modelElement, element);

                problems.Add(problem);
            }

            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(ProgrammingAndViewSchemaTypes);
            var topVisitor = new TopRowFilterVisitor();

            fragment.Accept(topVisitor);

            if (topVisitor.Count > 0)
            {
                var orderByvisitor = new OrderByVisitor();
                fragment.Accept(orderByvisitor);
                if (orderByvisitor.Count < 1)
                {
                    problems.Add(new SqlRuleProblem(Message, sqlObj, topVisitor.Statements[0]));
                }
            }

            return(problems);
        }
예제 #22
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)
            {
                return(problems);
            }
            var fragment = ruleExecutionContext.ScriptFragment.GetFragment(typeof(CreateProcedureStatement));

            IfStatementVisitor ifVisitor = new IfStatementVisitor();

            fragment.Accept(ifVisitor);

            if (!ifVisitor.Statements.Any())
            {
                return(problems);
            }

            foreach (var ifStatement in ifVisitor.NotIgnoredStatements(RuleId))
            {
                var tableVisitor = new NamedTableReferenceVisitor()
                {
                    TypeFilter = ObjectTypeFilter.PermanentOnly
                };
                ifStatement.ThenStatement?.Accept(tableVisitor);
                ifStatement.ElseStatement?.Accept(tableVisitor);
                problems.AddRange(tableVisitor.Statements.Select(s => new SqlRuleProblem(Message, sqlObj, s)));
            }

            return(problems);
        }
예제 #23
0
        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(CreateTableStatement));
            var tableName = sqlObj.Name.GetName();

            ColumnDefinitionVisitor columnVisitor = new ColumnDefinitionVisitor();

            fragment.Accept(columnVisitor);

            var longChars = columnVisitor.Statements
                            .Where(col => col.DataType != null && col.DataType.Name != null)
                            .Select(col => new
            {
                column = col,
                name   = col.ColumnIdentifier.Value,
                type   = col.DataType.Name.Identifiers.FirstOrDefault()?.Value,
                length = GetDataTypeLength(col)
            })
                            .Where(x => (_comparer.Equals(x.type, "char") || _comparer.Equals(x.type, "nchar")) && x.length > 9);

            problems.AddRange(longChars.Select(col => new SqlRuleProblem(Message, sqlObj, col.column)));

            return(problems);
        }
예제 #24
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 fkinfo = sqlObj.GetFKInfo();

            var table = ruleExecutionContext.SchemaModel.GetObject(Table.TypeClass, fkinfo.TableName, DacQueryScopes.All);

            if (!table.CheckForFkIndex(fkinfo.ColumnNames))
            {
                problems.Add(new SqlRuleProblem(Message, sqlObj));
                return(problems);
            }

            table = ruleExecutionContext.SchemaModel.GetObject(Table.TypeClass, fkinfo.ToTableName, DacQueryScopes.All);
            if (!table.CheckForFkIndex(fkinfo.ToColumnNames))
            {
                problems.Add(new SqlRuleProblem(Message, sqlObj));
                return(problems);
            }

            return(problems);
        }
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            var table       = ruleExecutionContext.ModelElement;
            var permissions = table.GetReferencing(Permission.SecuredObject);
            var readerRole  = new ObjectIdentifier("ReaderRole");

            var comparer = ruleExecutionContext.SchemaModel.CollationComparer;

            foreach (var permission in permissions)
            {
                var permissionType   = (PermissionType)permission.GetProperty(Permission.PermissionType);
                var permissionAction = (PermissionAction)permission.GetProperty(Permission.PermissionAction);

                var grantees = permission.GetReferenced(Permission.Grantee).Select(grantee => grantee.Name);

                if (grantees.Contains(readerRole, comparer) && permissionAction == PermissionAction.Grant && permissionType == PermissionType.Select)
                {
                    return(new List <SqlRuleProblem>());
                }
            }

            return(new List <SqlRuleProblem>()
            {
                new SqlRuleProblem("Table don't have permission for [ReaderRole]", table)
            });
        }
예제 #26
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 selectStatementVisitor = new SelectStatementVisitor();

            fragment.Accept(selectStatementVisitor);

            foreach (var select in selectStatementVisitor.Statements)
            {
                var selectStarVisitor = new SelectStarExpressionVisitor();
                select.AcceptChildren(selectStarVisitor);

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

            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 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);
        }
        /// <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)
            {
                return(problems);
            }

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

            var createTableVisitor = new CreateTableVisitor();

            fragment.Accept(createTableVisitor);

            var statements = createTableVisitor
                             .Statements
                             .Where(p => p.SchemaObjectName
                                    .Identifiers
                                    .Any(a => a.Value.StartsWith("#", System.StringComparison.InvariantCultureIgnoreCase)));

            foreach (var statement in statements)
            {
                var noCollationColumns = statement.Definition.ColumnDefinitions.Where(p => p.Collation == null &&
                                                                                      (((SqlDataTypeReference)p.DataType).SqlDataTypeOption == SqlDataTypeOption.VarChar ||
                                                                                       ((SqlDataTypeReference)p.DataType).SqlDataTypeOption == SqlDataTypeOption.Char ||
                                                                                       ((SqlDataTypeReference)p.DataType).SqlDataTypeOption == SqlDataTypeOption.NVarChar ||
                                                                                       ((SqlDataTypeReference)p.DataType).SqlDataTypeOption == SqlDataTypeOption.NChar));
                problems.AddRange(noCollationColumns.Select(s => new SqlRuleProblem(Message, sqlObj, s)));
            }

            return(problems);
        }
        private void AnalyzeQueries(IList <SqlRuleProblem> problems, TSqlFragment fragment,
                                    SqlRuleExecutionContext ruleExecutionContext)
        {
            // Find all queries in current checking fragment.
            var visitor = new GetQuerySpecificationsVisitor();

            fragment.Accept(visitor);
            foreach (var querySpecification in visitor.Queries)
            {
                // Get the specified tables in the query.
                var unspecifiedPartitions = CollectFromClause(ruleExecutionContext, querySpecification);

                // If the query isn't querying a partition table, we don't need to check it.
                if (unspecifiedPartitions.Count > 0)
                {
                    // Get all constraints in the query.
                    if (querySpecification.WhereClause != null)
                    {
                        SearchConstraints(querySpecification.WhereClause, unspecifiedPartitions);
                    }
                }

                // If there are any unspecified partitions left, these are considered problems.
                foreach (var unspecifiedPartition in unspecifiedPartitions)
                {
                    SqlRuleProblem problem = CreateProblem(ruleExecutionContext, unspecifiedPartition);
                    problems.Add(problem);
                }

                AnalyzeJoins(problems, ruleExecutionContext, querySpecification);
            }
        }
        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 binaryExpressionVisitor = new BinaryExpressionVisitor();
                whereClause.Accept(binaryExpressionVisitor);

                foreach (var comparison in binaryExpressionVisitor.NotIgnoredStatements(RuleId))
                {
                    if (CheckBinaryExpression(comparison).GetValueOrDefault(false))
                    {
                        problems.Add(new SqlRuleProblem(Message, sqlObj, comparison));
                    }
                }
            }

            return(problems);
        }
예제 #31
0
 /// <summary>
 /// Gets a formatted element name
 /// </summary>
 public static string GetElementName(TSqlObject modelElement, SqlRuleExecutionContext ruleExecutionContext, ElementNameStyle style)
 {
     // Get the element name using the built in DisplayServices. This provides a number of useful formatting options to
     // make a name user-readable
     var displayServices = ruleExecutionContext.SchemaModel.DisplayServices;
     string elementName = displayServices.GetElementName(modelElement, style);
     return elementName;
 }
 private static string GetElementName(SqlRuleExecutionContext ruleExecutionContext, TSqlObject modelElement)
 {
     // Get the element name using the built in DisplayServices. This provides a number of 
     // useful formatting options to
     // make a name user-readable
     var displayServices = ruleExecutionContext.SchemaModel.DisplayServices;
     string elementName = displayServices.GetElementName(modelElement, ElementNameStyle.EscapedFullyQualifiedName);
     return elementName;
 }
예제 #33
0
        public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            var tableElement = ruleExecutionContext.ModelElement;
            var tableName = GetElementName(ruleExecutionContext, tableElement);

            //Ensure that it's effectively an info table
            if (IsAnchor(tableElement))
                return OnAnalyze(tableName, tableElement).ToList();

            return new List<SqlRuleProblem>();
        }
예제 #34
0
        public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext context)
        {
            List<SqlRuleProblem> problems = new List<SqlRuleProblem>();
            _model = context.SchemaModel;

            // Query all top level user-defined objects in the model. This restricts scope to objects actually defined
            // in this model, rather than same database references, built in types, or system references
            foreach (TSqlObject tSqlObject in _model.GetObjects(DacQueryScopes.UserDefined))
            {
                AnalyzeObject(tSqlObject, problems);
            }

            return problems;
        }
        public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext context)
        {
            IList<SqlRuleProblem> problems = new List<SqlRuleProblem>();
            TSqlObject table = context.ModelElement;

            if (table.GetProperty<bool>(Table.MemoryOptimized))
            {
                // In this case we look up "Referencing" relationships. This is a way to iterate
                // over the objects that reference the current object. Note how the actual relationship
                // that we care about is defined on the View class rather than on the table.
                foreach (TSqlObject view in table.GetReferencing(View.BodyDependencies))
                {
                    ValidateViewHasSchemaBinding(context, view, table, problems);
                    ValidateViewHasNoIndexes(context, view, table, problems);
                }
            }

            return problems;
        }
        /// <summary>
        /// Check if the table has any datetime2 column, and then check if they have a scale of 7 or more.
        /// </summary>
        /// <param name="ruleExecutionContext"></param>
        /// <returns></returns>
        public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            List<SqlRuleProblem> problems = new List<SqlRuleProblem>();
            TSqlObject table = ruleExecutionContext.ModelElement;
            if (table != null)
            {
                foreach (var column in table.GetReferenced(Table.Columns))
                {
                    if (IsDateTime2WithExcessiveScale(column))
                    {
                        //DisplayServices is a useful helper service for formatting names
                        DisplayServices displayServices = ruleExecutionContext.SchemaModel.DisplayServices;
                        string formattedName = displayServices.GetElementName(column, ElementNameStyle.FullyQualifiedName);

                        string problemDescription = string.Format(DateTime2ColumnWithExcessiveScaleMsgFormat,
                            formattedName);
                        SqlRuleProblem problem = new SqlRuleProblem(problemDescription, table);
                        problems.Add(problem);
                    }
                }
            }
            return problems;
        }
        public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            var problems = new List<SqlRuleProblem>();

            var tableElement = ruleExecutionContext.ModelElement;
            var tableName = GetElementName(ruleExecutionContext, tableElement);

            //Ensure that it's effectively a dimension table
            if (tableElement.Name.HasName && tableElement.Name.Parts.Last().StartsWith("Dim", StringComparison.OrdinalIgnoreCase))
            {
                //Get the columns of the table
                var columns = tableElement.GetReferenced(Table.Columns);
                if (columns.Count() == 0)
                    problems.Add(new SqlRuleProblem(string.Format("The dimension table {0} has no column", tableName), tableElement));

                //Ensure that one of them is effecively an identity
                var identityColumn = columns.FirstOrDefault(c => c.GetProperty<bool>(Column.IsIdentity));
                if (identityColumn == null)
                    problems.Add(new SqlRuleProblem(string.Format("No identity column for the dimension table {0}", tableName), tableElement));
            }

            return problems;
            
        }
        /// <summary>
        /// Analysis is quite simple - the table's name is examined and if it ends with "View" then a problem
        /// is created
        /// </summary>
        /// <param name="ruleExecutionContext"></param>
        /// <returns></returns>
        public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            List<SqlRuleProblem> problems = new List<SqlRuleProblem>();
            TSqlObject table = ruleExecutionContext.ModelElement;
            if (table != null)
            {
                if (NameEndsInView(table.Name))
                {
                    // DisplayServices is a useful helper service for formatting names
                    DisplayServices displayServices = ruleExecutionContext.SchemaModel.DisplayServices;
                    string formattedName = displayServices.GetElementName(table, ElementNameStyle.FullyQualifiedName);

                    string problemDescription = string.Format(NameEndingInViewMsgFormat,
                                                              formattedName);
                    SqlRuleProblem problem = new SqlRuleProblem(problemDescription, table);
                    problems.Add(problem);
                }
            }

            return problems;
        }
        /// <summary>
        /// No Indexes of any kind are allowed on Views that reference a memory optimized table.
        /// </summary>
        private void ValidateViewHasNoIndexes(SqlRuleExecutionContext context, TSqlObject view, TSqlObject table, IList<SqlRuleProblem> problems)
        {
            foreach (TSqlObject index in view.GetReferencing(Index.IndexedObject))
            {
                string description = string.Format(CultureInfo.CurrentCulture,
                    RuleResources.ViewsOnMemoryOptimizedTable_IndexProblemDescription,
                    RuleUtils.GetElementName(context, index),
                    RuleUtils.GetElementName(context, view),
                    RuleUtils.GetElementName(context, table));
                TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(index);

                // Note that nameFragment can be null - in this case the index's position information will be used.
                // This is just a little less precise than pointing to the position of the name for that index
                problems.Add(new SqlRuleProblem(description, index, nameFragment));

            }
        }
        private static void AnalyzeColumns(
            SqlRuleExecutionContext context,
            TSqlObject index, 
            string defaultCollation,
            IList<SqlRuleProblem> problems)
        {
            foreach (TSqlObject column in index.GetReferenced(Index.Columns)
                                               .Where(column => IsCharacterColumn(column)))
            {
                // Fall back on the default project collation if none is defined for the specific column
                 string collation = column.GetProperty<string>(Column.Collation) ?? defaultCollation ?? string.Empty;
                if (!collation.EndsWith(Bin2Ending, StringComparison.OrdinalIgnoreCase))
                {
                    // Error looks liks "Index <name> on column <name> should have a BIN2 collation instead of <collation>"
                    // Choosing to add 1 problem per-column. This will cause more warnings in the error manager but is more precise
                    string errorMsg = string.Format(CultureInfo.CurrentCulture,
                        context.RuleDescriptor.DisplayDescription,
                        RuleUtils.GetElementName(index, context, ElementNameStyle.EscapedFullyQualifiedName),
                        RuleUtils.GetElementName(column, context, ElementNameStyle.EscapedFullyQualifiedName),
                        collation);

                    SqlRuleProblem problem = new SqlRuleProblem(errorMsg, index);
                    problems.Add(problem);
                }
            }
        }
        public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext context)
        {
            IList<SqlRuleProblem> problems = new List<SqlRuleProblem>();
            TSqlObject index = context.ModelElement;

            if (!IsIndexOnMemoryOptimizedTable(index))
            {
                // Only examining memory optimized tables, anything else can be ignored
                // Note the call to the Table.MemoryOptimized property: this is where we verify the in-memory behavior
                return problems;
            }

            TSqlObject databaseOptions = context.SchemaModel
                .GetObjects(DacQueryScopes.UserDefined, DatabaseOptions.TypeClass).SingleOrDefault();

            if (databaseOptions == null)
            {
                // This should never happen as the database options are automatically created
                return problems;
            }

            string defaultCollation = databaseOptions.GetProperty<string>(DatabaseOptions.Collation);

            AnalyzeColumns(context, index, defaultCollation, problems);

            return problems;
        }
예제 #42
0
        /// <summary>
        /// For element-scoped rules the Analyze method is executed once for every matching object in the model. 
        /// </summary>
        /// <param name="ruleExecutionContext">The context object contains the TSqlObject being analyzed, a TSqlFragment
        /// that's the AST representation of the object, the current rule's descriptor, and a reference to the model being
        /// analyzed.
        /// </param>
        /// <returns>A list of problems should be returned. These will be displayed in the Visual Studio error list</returns>
        public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            IList<SqlRuleProblem> problems = new List<SqlRuleProblem>();

            TSqlObject modelElement = ruleExecutionContext.ModelElement;

            // this rule does not apply to inline table-valued function
            // we simply do not return any problem in that case.
            if (IsInlineTableValuedFunction(modelElement))
            {
                return problems;
            }

            string elementName = RuleUtils.GetElementName(ruleExecutionContext, modelElement);

            // The rule execution context has all the objects we'll need, including the fragment representing the object,
            // and a descriptor that lets us access rule metadata
            TSqlFragment fragment = ruleExecutionContext.ScriptFragment;
            RuleDescriptor ruleDescriptor = ruleExecutionContext.RuleDescriptor;

            // To process the fragment and identify WAITFOR DELAY statements we will use a visitor
            //
            WaitForDelayVisitor visitor = new WaitForDelayVisitor();
            fragment.Accept(visitor);
            IList<WaitForStatement> waitforDelayStatements = visitor.WaitForDelayStatements;

            // Create problems for each WAITFOR DELAY statement found
            foreach (WaitForStatement waitForStatement in waitforDelayStatements)
            {
                // When creating a rule problem, always include the TSqlObject being analyzed. This is used to determine
                // the name of the source this problem was found in and a best guess as to the line/column the problem was found at
                //
                // In addition if you have a specific TSqlFragment that is related to the problem also include this
                // since the most accurate source position information (start line and column) will be read from the fragment
                SqlRuleProblem problem = new SqlRuleProblem(
                                            String.Format(CultureInfo.CurrentCulture, ruleDescriptor.DisplayDescription, elementName),
                                            modelElement,
                                            waitForStatement);
                problems.Add(problem);
            }
            return problems;
        }
예제 #43
0
 /// <summary>
 /// Gets a formatted element name with the default style <see cref="ElementNameStyle.EscapedFullyQualifiedName"/>
 /// </summary>
 public static string GetElementName(SqlRuleExecutionContext ruleExecutionContext, TSqlObject modelElement)
 {
     return GetElementName(modelElement, ruleExecutionContext, ElementNameStyle.EscapedFullyQualifiedName);
 }
 /// <summary>
 // Views must be schema bound if they reference a memory optimized table
 /// </summary>
 private static void ValidateViewHasSchemaBinding(SqlRuleExecutionContext context, TSqlObject view, TSqlObject table,
     IList<SqlRuleProblem> problems)
 {
     if (!view.GetProperty<bool>(View.WithSchemaBinding))
     {
         string description = string.Format(CultureInfo.CurrentCulture,
             RuleResources.ViewsOnMemoryOptimizedTable_SchemaBindingProblemDescription,
             RuleUtils.GetElementName(context, view),
             RuleUtils.GetElementName(context, table));
         TSqlFragment nameFragment = TsqlScriptDomUtils.LookupSchemaObjectName(view);
         problems.Add(new SqlRuleProblem(description, view, nameFragment));
     }
 }
예제 #45
0
 public override IList<SqlRuleProblem> Analyze(SqlRuleExecutionContext context)
 {
     TSQLSmellWorker Worker = new TSQLSmellWorker(context, RuleId);
     return (Worker.Analyze());
 }
예제 #46
0
 public TSQLSmellWorker(SqlRuleExecutionContext context,string ruleID)
  {
      _model = context.SchemaModel;
      _ruleID = ruleID;
  }