예제 #1
0
 public MigrationRunner(IOptions <MigrationRunnerOptions> options,
                        IProviderCollection providerCollection, IMigrationFilesLoader migrationFilesLoader)
 {
     _options              = options;
     _providerCollection   = providerCollection;
     _migrationFilesLoader = migrationFilesLoader;
 }
예제 #2
0
 public CommandMigrationRunner(ILogger <CommandMigrationRunner> logger, IProviderCollection providerCollection,
                               MigrationOptionsLoader migrationOptionsLoader)
 {
     _logger                 = logger;
     _providerCollection     = providerCollection;
     _migrationOptionsLoader = migrationOptionsLoader;
 }
예제 #3
0
        public static IIdentifiedSource ToXmlSettings(this string text, IProviderCollection providers)
        {
            var settings = new XmlStringSettings(text);

            settings.Providers = providers;
            return(settings);
        }
 public MigrationOptionsLoader(ILogger <MigrationOptionsLoader> logger,
                               IProviderCollection providerCollection,
                               IConnectionStringsProcessorCollection connectionStringsProcessorCollection)
 {
     _logger             = logger;
     _providerCollection = providerCollection;
     _connectionStringsProcessorCollection = connectionStringsProcessorCollection;
 }
예제 #5
0
        public override void Execute(Database database, IProviderCollection providers)
        {
            ITableImportance importance = providers.GetProvider <TableDataImportance>();

            if (importance == null)
            {
                importance = providers.GetProvider <PageRank>();
            }

            this._importanceBackend = importance;
        }
예제 #6
0
        public override void Execute(DataTable table, IProviderCollection providers)
        {
            if (table.Cardinality <= 1)
            {
                return;
            }

            double tableInformationContent = Math.Log(table.Cardinality, 2);

            foreach (var column in table.Columns.Where(c => validTypes.Contains(c.DataType)))
            {
                double res = GetMultiColumnEntropy(table, column);
                if (res < 0)
                {
                }
                _columnInformationContent[column] = res;
                tableInformationContent          += res;
            }
            this._tableInformationContent[table] = tableInformationContent;
        }
예제 #7
0
 public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
 {
     foreach (var table in database.Tables)
     {
         foreach (var fk in table.ForeignKeys)
         {
             bool doesIndexExist = table.Indices.Any(ix =>
                                                          {
                                                              if (ix.Columns.Count < fk.ColumnPairs.Count)
                                                                  return false;
                                                              for (int i = 0; i < fk.ColumnPairs.Count; i++)
                                                              {
                                                                  var fkColumn = fk.ColumnPairs[i].FKColumn;
                                                                  if (!ix.Columns[i].Equals(fkColumn))
                                                                      return false;
                                                              }
                                                              return true;
                                                          });
             if (!doesIndexExist)
             {
                 var dt = new DataTable();
                 dt.Columns.Add("Column", typeof(Column));
                 foreach (var col in fk.ColumnPairs)
                     dt.Rows.Add(col.FKColumn);
                 issueCollector.ReportIssue(new Issue(this, this.DefaultSeverity.Value)
                                                {
                                                    Name = "Missing Index on Foreign-Key Column(s)",
                                                    Context = new TableContext(table),
                                                    Description = new Description("Missing index on the columns used in foreign-key '{0}' in table '{1}'", fk.ForeignKeyName, table),
                                                    ExtendedDescription = new Description("{0}", dt)
                                                });
             }
         }
     }
 }
예제 #8
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            var tables = (from tab in database.Tables
                          where tab.PrimaryKey != null
                          select tab).ToList();

            foreach (var table in tables)
            {
                for (int i = 0; i < table.PrimaryKey.Columns.Count; i++)
                {
                    if (table.PrimaryKey.Columns[i] != table.Columns[i])
                    {
                        var issue = new Issue(this, this.DefaultSeverity.Value);
                        issue.Name        = "Primary-Key Column(s) Not Positioned First";
                        issue.Description = new Description("The columns in primary key in table {0} should be positioned first, and in the same order as the primary-key index", table);
                        issue.Context     = new TableContext(table);
                        issueCollector.ReportIssue(issue);
                        break;
                    }
                }
            }
        }
예제 #9
0
 public abstract void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers);
예제 #10
0
 public ProviderLoader(IProviderCollection providers)
 {
     _providers = providers;
 }
예제 #11
0
 public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
 {
     if (table.Cardinality == 0)
     {
         issueCollector.ReportIssue(new Issue(this, Severity.Medium)
         {
             Name        = "Empty Table",
             Context     = new TableContext(table),
             Description = new Description("Table {0} is empty", table)
         });
     }
 }
예제 #12
0
        private void Write(String dirName, DatabaseLint dblint)
        {
            this.scoring = new IScoringImpl();
            this.scoring.CalculateScores(dblint);

            if (DBLint.Settings.IsNormalContext)
            {
                //Save run for incremental viewing
                //File name is a timestamp
                DateTime now      = DateTime.Now;
                String   fileName = String.Format("{0}{1}{2}{3}{4}{5}.xml", now.Year, now.Month, now.Day, now.Hour,
                                                  now.Minute, now.Second);
                //Folder, i.e.: runs/dbname/
                String folder   = Settings.INCREMENTAL_FOLDER + "testtest"; // dblint.DatabaseModel.DatabaseName;
                String filePath = folder + "/" + fileName;
                if (!Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }


                //Create run
                DBLint.IncrementalRuns.Run run = new IncrementalRuns.Run(dblint.DatabaseModel, dblint.IssueCollector, scoring.GetScores());
                //Write run
                using (FileStream writer = new FileStream(filePath, FileMode.Create))
                {
                    DataContractSerializer ser = new DataContractSerializer(typeof(DBLint.IncrementalRuns.Run));
                    ser.WriteObject(writer, run);
                    writer.Flush();
                }
            }

            DirectoryInfo dir = new DirectoryInfo(dirName);

            int tableNameCounter = 1;

            foreach (Table table in dblint.DatabaseModel.Tables)
            {
                String tName = "table" + tableNameCounter.ToString();
                this.tableNames.Add(table, tName);
                this.tableFiles.Add(table, "tables/" + tName + ".html");
                tableNameCounter++;
            }

            this.dblint = dblint;

            this.formatter = new HTMLDescriptionFormatter(this.tableFiles);

            IssueCollector issues = dblint.IssueCollector;

            //Create result directory if it does not exist
            if (!dir.Exists)
            {
                dir.Create();
            }

            VelocityContext context = new VelocityContext();

            context.Put("db", dblint.DatabaseModel);
            context.Put("totalScore", this.scoring.GetScore());
            context.Put("issuesTotal", issues.Count());
            context.Put("rulesExecuted", this.getRulesExecuted());
            context.Put("ruleTypes", this.getRuleTypes());
            context.Put("formatter", this.formatter);
            context.Put("HTMLBuilder", this);
            context.Put("summaries", this.dblint.ExecutionSummary);
            context.Put("executionTime", this.formatTimeSpan(this.dblint.ExecutionSummary.ExecutionTime));

            //Pagerank
            IProviderCollection providers = dblint.RuleController.ProviderCollection;
            var rank = providers.GetProvider <DBLint.Rules.SchemaProviders.ImportanceProvider>();

            //List all tables
            var tables = (from t in dblint.DatabaseModel.Tables
                          select new
            {
                Table = t,
                Name = t.TableName,
                IssueCount = issues.GetIssues(t).Count(),
                Score = this.scoring.GetScore(t),
                Importance = Math.Round(rank[t], 1)
            }).ToList();

            context.Put("tables", tables);

            //Bottom tables
            var bottom = tables.OrderBy(t => t.Score).Take(5).ToList();

            context.Put("bottomTables", bottom);

            int groupId = 0; //Used in the template to identify a group of issues
            //Group issues by name
            var issueGroups = (from i in issues
                               group i by i.Name into g
                               orderby g.First().Severity
                               select new
            {
                Name = g.Key,
                Count = g.Count(),
                Issues = g,
                GroupID = ++groupId,
                Severity = g.First().Severity
            }).ToList();

            context.Put("issueGroups", issueGroups);

            //Put issueGroups into severity groups
            var severityGroups = (from issueGroup in issueGroups
                                  group issueGroup by issueGroup.Severity into g
                                  orderby g.First().Severity
                                  select new
            {
                Severity = g.First().Severity,
                IssueGroups = g
            }
                                  );

            context.Put("severityGroups", severityGroups);

            //Incremental runs list
            var diffs = new List <DBLint.IncrementalRuns.Diff>();

            if (DBLint.Settings.IsNormalContext)
            {
                //Incremental runs
                try
                {
                    var runs = DBLint.IncrementalRuns.Run.GetRuns(dblint.DatabaseModel.DatabaseName, 5).ToList();
                    for (int i = 1; i < runs.Count; i++)
                    {
                        var diff = new DBLint.IncrementalRuns.Diff();
                        diff.Compare(runs[i], runs[i - 1]);
                        diffs.Add(diff);
                    }
                }
                catch { }
                context.Put("diffs", diffs);
            }
            //Create template for the main html page
            Template template = Velocity.GetTemplate("mainpage.vm");

            //Create outputstream for the main page
            TextWriter htmlOut = new StreamWriter(Path.Combine(dir.FullName, "mainpage.html"));

            //Write template
            template.Merge(context, htmlOut);
            htmlOut.Close();

            //Write issue groups
            String issuePath = Path.Combine(dir.FullName, "issues");

            if (!Directory.Exists(issuePath))
            {
                Directory.CreateDirectory(issuePath);
            }
            Template issueGroupTemplate = Velocity.GetTemplate("issuegroup.vm");

            formatter.PathPrefix = "../";
            foreach (var g in issueGroups)
            {
                context.Put("groupIssues", g.Issues);
                TextWriter issueOut = new StreamWriter(Path.Combine(issuePath, g.GroupID.ToString() + ".html"));
                issueGroupTemplate.Merge(context, issueOut);
                issueOut.Close();
            }
            if (DBLint.Settings.IsNormalContext)
            {
                //Write diffs/increments to files:
                String incPath = Path.Combine(dir.FullName, "increments");
                if (!Directory.Exists(incPath))
                {
                    Directory.CreateDirectory(incPath);
                }
                Template incrementTemplate = Velocity.GetTemplate("increment.vm");
                int      diffId            = 0;
                foreach (var diff in diffs)
                {
                    diffId++;
                    context.Put("diff", diff);
                    TextWriter incOut = new StreamWriter(Path.Combine(incPath, diffId.ToString() + ".html"));
                    incrementTemplate.Merge(context, incOut);
                    incOut.Close();
                }
            }

            formatter.PathPrefix = "";
            writeTableViews(dirName);
        }
예제 #13
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            var columns = database.Tables.SelectMany(t => t.Columns).Where(c => c.ColumnName.Length < this.MinimalCharactersInName.Value);

            foreach (var column in columns)
            {
                issueCollector.ReportIssue(new Issue(this, this.DefaultSeverity.Value)
                {
                    Name        = "Too Short Column Name",
                    Description = new Description("Column '{0}' has a shorter name than allowed in table {1}.", column, column.Table),
                    Context     = new ColumnContext(column)
                });
            }
        }
예제 #14
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            foreach (var schema in database.Schemas)
            {
                var columnGroups = (from col in schema.Columns
                                    where col.DataType == DataType.VARCHAR && col.CharacterMaxLength > minLength.Value
                                    orderby col.CharacterMaxLength ascending
                                    group col by col.CharacterMaxLength into g
                                    select g).ToList();

                var group = new List <List <Column> >();
                for (int i = 0; i < columnGroups.Count - 1; i++)
                {
                    if (group.Count == 0)
                    {
                        group.Add(columnGroups[i].ToList());
                    }
                    if (Math.Abs(columnGroups[i].First().CharacterMaxLength - columnGroups[i + 1].First().CharacterMaxLength) <= threshold.Value)
                    {
                        group.Add(columnGroups[i + 1].ToList());
                    }
                    else
                    {
                        if (group.Count > 1)
                        {
                            issueCollector.ReportIssue(GetIssue(group));
                        }
                        group.Clear();
                    }
                }
                if (group.Count > 1)
                {
                    issueCollector.ReportIssue(GetIssue(group));
                }
            }
        }
예제 #15
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            var tables = database.Tables.Where(t => t.PrimaryKey == null);

            foreach (var table in tables)
            {
                Issue issue = new Issue(this, this.DefaultSeverity.Value);
                issue.Name        = "Missing Primary Key";
                issue.Context     = new TableContext(table);
                issue.Description = new Description("Table {0} is missing a primary key", table);
                issueCollector.ReportIssue(issue);
            }
        }
예제 #16
0
        public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
        {
            var informationContent = providers.GetProvider <InformationContent>();

            if (table.PrimaryKey == null || table.Cardinality < MinRows.Value)
            {
                return;
            }
            var pkcolumns = table.PrimaryKey.Columns;
            var escaper   = table.Database.Escaper;
            // Heuristic: Only check columns storing a lot of entropy

            var entropyOrderedCOlumns = pkcolumns.OrderByDescending(col => informationContent[col]).ToArray();

            double maxPossibleCardinality = 1;
            var    currentColumns         = new List <Column>(entropyOrderedCOlumns.Length);
            var    first = true;
            var    currentColumnsString = new StringBuilder();

            foreach (var col in entropyOrderedCOlumns)
            {
                currentColumns.Add(col);
                if (currentColumns.Count == entropyOrderedCOlumns.Length)
                {
                    break; // Last column added. It is known to be a key.
                }
                maxPossibleCardinality *= informationContent[col];
                if (table.Cardinality - maxPossibleCardinality > 0.2f)
                {
                    continue; // If not enough entropy to generate a higher card. no need to query the data.
                }
                var escapedCol = escaper.Escape(col);
                if (first)
                {
                    currentColumnsString.AppendFormat("{0}", escapedCol);
                    first = false;
                }
                else
                {
                    currentColumnsString.AppendFormat(", {0}", escapedCol);
                }

                var query = string.Format(@"SELECT  COUNT(*)
                                            FROM    ( SELECT    COUNT(*) AS rowcnt
                                                      FROM      {0}
                                                      GROUP BY  {1}
                                                    ) AS exp1
                                            WHERE   rowcnt > 1 ", escaper.Escape(table), currentColumnsString.ToString());
                var res   = table.QueryTable(query);
                if (res is DBNull)
                {
                    break;
                }

                var num = Convert.ToInt32(res);
                if (num == 0)
                {
                    issueCollector.ReportIssue(new Issue(this, this.Severity)
                    {
                        Name                = "Defined Primary Key is not a Minimal Key",
                        Context             = new TableContext(table),
                        Description         = new Description("Primary key for table {0}, is a superkey.", table),
                        ExtendedDescription = new Description("Columns {0} are enough to uniquely identify a tuple. Currently used are {1}", currentColumns, table.PrimaryKey.Columns),
                    });
                    break;
                }
            }
        }
예제 #17
0
        public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
        {
            if (table.Cardinality < MinRows.Value)
            {
                return;
            }

            //Find candidates (text columnns)
            var textColumns = table.Columns.Where(c => c.DataType == DataTypes.DataType.VARCHAR ||
                                                  c.DataType == DataTypes.DataType.CHAR).ToList();
            var fk_columns = (from fks in table.ForeignKeys
                              from colpair in fks.ColumnPairs
                              select colpair.FKColumn);

            textColumns = textColumns.Where(c => fk_columns.Contains(c) == false).ToList();

            List <Candidate> candidates = textColumns.Select(c => new Candidate(c)).ToList();

            //Prune candidates
            using (var rowEnumerable = table.GetTableRowEnumerable())
                foreach (DataRow row in rowEnumerable)
                {
                    foreach (var candidate in candidates.ToArray())
                    {
                        Object value = row[candidate.Column.ColumnName];
                        if (value is DBNull || (value is String && ((String)value) == ""))
                        {
                            continue;
                        }

                        if (candidate.Values.ContainsKey(value))
                        {
                            continue;
                        }
                        else
                        {
                            candidate.Values.Add(value, 0);
                        }

                        if (candidate.Values.Count > this.MaximumValues.Value)
                        {
                            candidates.Remove(candidate);
                        }
                    }
                }

            //Report issues
            foreach (var candidate in candidates)
            {
                if (candidate.Values.Count < MinimumValues.Value)
                {
                    break;
                }

                System.Data.DataTable valuesTable = new System.Data.DataTable();
                valuesTable.Columns.Add("Values", typeof(String));
                foreach (Object value in candidate.Values.Keys)
                {
                    var row = valuesTable.NewRow();
                    row[0] = value.ToString();
                    valuesTable.Rows.Add(row);
                }

                Issue issue = new Issue(this, this.Severity);
                issue.Name                = "Column Values from a Small Domain";
                issue.Description         = new Description("Values in column '{0}' indicates that an enum could be appropriate", candidate.Column.ColumnName);
                issue.ExtendedDescription = new Description("{0} rows checked.\n\n{1}", table.Cardinality, valuesTable);
                issue.Context             = new ColumnContext(candidate.Column);
                issueCollector.ReportIssue(issue);
            }
        }
예제 #18
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            var tables = from tab in database.Tables
                         where tab.Indices.Count > 1
                         select tab;

            try
            {
                var start = DateTime.Now;
                foreach (var table in tables)
                {
                    var          sortedIndices    = table.Indices.OrderByDescending(t => t.Columns.Count).ToList();
                    List <Index> excludeIndex     = new List <Index>();
                    List <Index> redundantIndices = new List <Index>();
                    for (int i = 0; i < sortedIndices.Count - 1; i++)
                    {
                        if (!excludeIndex.Contains(sortedIndices[i]))
                        {
                            for (int j = i + 1; j < sortedIndices.Count; j++)
                            {
                                var subIndexLen = sortedIndices[j].Columns.Count;
                                if (sortedIndices[i].Columns.ToList().GetRange(0, subIndexLen).SequenceEqual(sortedIndices[j].Columns))
                                {
                                    redundantIndices.Add(sortedIndices[j]);
                                    if (!excludeIndex.Contains(sortedIndices[j]))
                                    {
                                        excludeIndex.Add(sortedIndices[j]);
                                    }
                                }
                            }
                            if (redundantIndices.Count > 0)
                            {
                                var issue = new Issue(this, this.DefaultSeverity.Value);
                                issue.Name        = "Redundant Index";
                                issue.Context     = new TableContext(table);
                                issue.Description = new Description("Redundant indices for the index '{0}' in table {1}",
                                                                    sortedIndices[i], table);
                                issue.ExtendedDescription = new Description("The indices in the second table below are redundant to the index:\n\n{0}\n\nRedundant indices:\n\n{1}",
                                                                            GetIndexTable(new List <Index>()
                                {
                                    sortedIndices[i]
                                }), GetIndexTable(redundantIndices));
                                issueCollector.ReportIssue(issue);
                            }
                        }
                        redundantIndices.Clear();
                    }
                }
                var end = DateTime.Now;
                //Console.WriteLine("redundant indices time: {0}", (end - start));
            }
            catch (Exception ex)
            {
                Console.WriteLine(String.Format("\tError in redundant indices:\n{0}", ex.Message));
                throw ex;
            }
        }
예제 #19
0
        public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
        {
            if (table.Cardinality < MinRows.Value)
            {
                return;
            }

            var candidateColumns = table.Columns.Where(c => DataTypes.DataTypesLists.TextTypes().Contains(c.DataType));

            Dictionary <Column, int> candidates = new Dictionary <Column, int>(); //column -> blank_count

            candidateColumns.ToList().ForEach(c => candidates.Add(c, 0));
            using (var rowEnumerable = table.GetTableRowEnumerable())
                foreach (var row in rowEnumerable)
                {
                    foreach (var candidate in candidates.Keys.ToArray())
                    {
                        Object val = row[candidate.ColumnName];
                        if (val is String && val.Equals(String.Empty))
                        {
                            candidates[candidate] += 1;
                        }
                    }
                }

            foreach (var candidate in candidates)
            {
                float percentBlanks = ((float)candidate.Value / table.Cardinality) * 100;
                if (percentBlanks > Threshold.Value)
                {
                    Issue issue = new Issue(this, this.Severity);
                    issue.Name    = "The Empty String Used to Represent Null";
                    issue.Context = new ColumnContext(candidate.Key);

                    if (candidate.Key.IsNullable)
                    {
                        issue.Description = new Description("The nullable column '{0}' contains {2} rows of which {1} are the empty string. Consider using null",
                                                            candidate.Key.ColumnName, candidate.Value, table.Cardinality);
                    }
                    else
                    {
                        issue.Description = new Description("The not-null column '{0}' contains {2} rows of which {1} are the empty string",
                                                            candidate.Key.ColumnName, candidate.Value, table.Cardinality);
                        issue.ExtendedDescription = new Description("Consider removing the not-null constraint and use null to represent non-existing values");
                    }

                    issueCollector.ReportIssue(issue);
                }
            }
        }
예제 #20
0
        public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
        {
            if (table.Cardinality < MinValues.Value)
            {
                return;
            }

            var columns = table.QueryableColumns.Where(c => DataTypesLists.TextTypes().Contains(c.DataType));

            if (columns.Count() == 0)
            {
                return;
            }

            var testColumns = columns.Select(c => new TestColumn(c)).ToList();

            using (var rowEnumerable = table.GetTableRowEnumerable())
                foreach (var row in rowEnumerable)
                {
                    foreach (var testColumn in testColumns)
                    {
                        Object val = row[testColumn.Column.ColumnName];

                        if (val is String)
                        {
                            String str = val as String;
                            if (str.Length < 1)
                            {
                                continue;
                            }

                            testColumn.ValueCount += 1;
                            if (str[0] == char.ToLower(str[0]))
                            {
                                testColumn.LowercaseStart += 1;
                            }
                            else
                            {
                                testColumn.UppercaseStart += 1;
                            }
                        }
                    }
                }

            foreach (var testColumn in testColumns)
            {
                if (testColumn.ValueCount <= this.MinValues.Value)
                {
                    continue;
                }

                float lowerPercent = ((float)testColumn.LowercaseStart / testColumn.ValueCount) * 100;
                float upperPercent = ((float)testColumn.UppercaseStart / testColumn.ValueCount) * 100;

                float lowest = Math.Min(lowerPercent, upperPercent);
                if (lowest < Threshold.Value && lowest != 0)
                {
                    Issue issue = new Issue(this, this.Severity);
                    issue.Name                = "Inconsistent Casing of First Character in Text Column";
                    issue.Context             = new ColumnContext(testColumn.Column);
                    issue.Description         = new Description("Inconsistent casing of first character in column '{0}'", testColumn.Column);
                    issue.ExtendedDescription = new Description("{0}% starts with lowercase\n{1}% starts with uppercase", lowerPercent, upperPercent);
                    issueCollector.ReportIssue(issue);
                }
            }
        }
예제 #21
0
        public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
        {
            if (table.Cardinality < this.MinRows.Value)
            {
                return;
            }

            var candidates = table.QueryableColumns.Where(c => c.DefaultValue != null).ToList();

            using (var rowEnumerable = table.GetTableRowEnumerable())
            {
                foreach (var row in rowEnumerable)
                {
                    foreach (var candidateColumn in candidates.ToArray())
                    {
                        Object val = row[candidateColumn.ColumnName];
                        if (!val.ToString().Equals(candidateColumn.DefaultValue))
                        {
                            candidates.Remove(candidateColumn);
                        }
                    }

                    if (candidates.Count == 0)
                    {
                        break;
                    }
                }
            }

            foreach (var candidateColumn in candidates)
            {
                if (candidateColumn.DefaultValue == "0" || candidateColumn.DefaultValue == "1")
                {
                    continue;
                }

                Issue issue = new Issue(this, this.Severity);
                issue.Name        = "All Values Equals the Default Value";
                issue.Context     = new ColumnContext(candidateColumn);
                issue.Description = new Description("All {0} values in column '{1}' equals default value '{2}'. Is the column necessary?",
                                                    table.Cardinality, candidateColumn.ColumnName, candidateColumn.DefaultValue);
                issueCollector.ReportIssue(issue);
            }
        }
예제 #22
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            foreach (var table in database.Tables.Where(t => t.PrimaryKey != null && t.UniqueConstraints.Count > 0))
            {
                foreach (var uq in table.UniqueConstraints)
                {
                    if (uq.Columns.All(c => table.PrimaryKey.Columns.Contains(c)))
                    {
                        System.Data.DataTable descTable = new System.Data.DataTable();
                        descTable.Columns.Add("PK Column(s)", typeof(String));
                        descTable.Columns.Add("UK Column(s)", typeof(String));
                        var row = descTable.NewRow();
                        row[0] = String.Join("\n", table.PrimaryKey.Columns.Select(c => c.ColumnName));
                        row[1] = String.Join("\n", uq.Columns.Select(c => c.ColumnName));

                        descTable.Rows.Add(row);

                        if (uq.Columns.Count == table.PrimaryKey.Columns.Count)
                        {
                            issueCollector.ReportIssue(new Issue(this, this.DefaultSeverity.Value)
                            {
                                Context             = new TableContext(table),
                                Description         = new Description("Columns in the primary key in table '{0}' is the same as the columns in a unique constraint", table),
                                ExtendedDescription = new Description("{0}", descTable),
                                Name = this.Name
                            });
                        }
                        else
                        {
                            issueCollector.ReportIssue(new Issue(this, this.DefaultSeverity.Value)
                            {
                                Context             = new TableContext(table),
                                Description         = new Description("The columns in a unique constraint in table '{0}' is a subset of the primary key", table),
                                ExtendedDescription = new Description("The primary key is a super key. Consider reducing the number of columns in the primary key.\n\n {0}", descTable),
                                Name = this.Name
                            });
                        }
                    }
                }
            }
        }
예제 #23
0
        public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
        {
            var textColumns = table.Columns.Where(c => DataTypes.DataTypesLists.TextTypes().Contains(c.DataType));
            var candidates  = textColumns.Select(c => new Candidate(c)).ToList();

            using (var rowEnumerable = table.GetTableRowEnumerable())
                foreach (var row in rowEnumerable)
                {
                    foreach (var candidate in candidates.ToArray())
                    {
                        Object val = row[candidate.Column.ColumnName];

                        if (val is DBNull || (val is String) == false)
                        {
                            continue;
                        }

                        String    str  = (String)val;
                        ValueType type = Classifier.Classify(str);

                        if (type != ValueType.Date && type != ValueType.Float && type != ValueType.Int)
                        {
                            candidates.Remove(candidate);
                            continue;
                        }

                        if (candidate.ValuesFound == 0)
                        {
                            candidate.Type = type;
                        }

                        if (type != candidate.Type)
                        {
                            candidates.Remove(candidate);
                        }
                        else
                        {
                            candidate.ValuesFound += 1;
                        }
                    }

                    if (candidates.Count == 0)
                    {
                        break;
                    }
                }

            foreach (var candidate in candidates)
            {
                if (candidate.ValuesFound < this.minValues.Value)
                {
                    continue;
                }

                Issue i = new Issue(this, this.Severity);
                i.Name        = "Numbers or Dates Stored in Varchar Column";
                i.Context     = new ColumnContext(candidate.Column);
                i.Description = new Description("The varchar column '{0}' is used to store values of type '{1}'", candidate.Column, candidate.Type.ToString());
                issueCollector.ReportIssue(i);
            }
        }
예제 #24
0
 public virtual void Finalize(Database database, IProviderCollection providers)
 {
 }
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            foreach (var table in database.Tables)
            {
                var colGroups = (from col in table.Columns
                                 let colName = Regex.Replace(col.ColumnName, @"\d+$", "")
                                               group col by colName into colGroup
                                               where colGroup.Count() > 1
                                               select new { Columns = colGroup.ToList() }).ToList();

                var inconsistentGroups = (from colGroup in colGroups
                                          where !colGroup.Columns.TrueForAll(c => c.DataType == colGroup.Columns.First().DataType)
                                          select colGroup.Columns).ToList();

                foreach (var incGroup in inconsistentGroups)
                {
                    var dt = new DataTable();
                    dt.Columns.Add("Column Name");
                    dt.Columns.Add("Data Type");
                    foreach (var col in incGroup.Select(c => c))
                    {
                        var row = dt.NewRow();
                        row[0] = col.ColumnName;
                        row[1] = col.DataType;
                        dt.Rows.Add(row);
                    }

                    var issue = new Issue(this, this.DefaultSeverity.Value);
                    issue.Name                = this.Name;
                    issue.Context             = new TableContext(table);
                    issue.Description         = new Description("Sequence of related columns in table '{0}' do not have the same data type", table);
                    issue.ExtendedDescription = new Description("Inconsistent data types for the following columns:\n{0}", dt);
                    issueCollector.ReportIssue(issue);
                }
            }
        }
예제 #26
0
 public static IIdentifiedSource ToXmlSettings(this string text, IProviderCollection providers)
 {
     var settings = new XmlStringSettings(text);
     settings.Providers = providers;
     return settings;
 }
예제 #27
0
        public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
        {
            var values  = new Dictionary <Column, HashSet <Object> >();
            var columns = (from fk in table.ForeignKeys
                           from colPair in fk.ColumnPairs
                           select colPair.FKColumn).ToList();

            if (!columns.All(c => table.QueryableColumns.Contains(c)))
            {
                return;
            }

            columns.ForEach(c => values.Add(c, new HashSet <Object>()));

            using (var rowEnumerable = table.GetTableRowEnumerable())
                foreach (var row in rowEnumerable)
                {
                    foreach (var column in columns)
                    {
                        Object val = row[column.ColumnName];
                        if (values[column].Contains(val))
                        {
                            return;
                        }
                        else
                        {
                            values[column].Add(val);
                        }
                    }
                }

            Issue issue = new Issue(this, this.Severity);

            issue.Name        = "Unnecessary One-to-One Relational Table";
            issue.Context     = new TableContext(table);
            issue.Description = new Description("The data in table {0} represents a one-to-one relationship.", table);
            issueCollector.ReportIssue(issue);
        }
예제 #28
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            // Select only column of type 'char' and only if the max length is larger than 20 and
            // if the default value fills below 50% of the possible max length
            var columnsToCheck = (from col in database.Columns
                                  where col.DataType == DataType.CHAR &&
                                  col.CharacterMaxLength > MaxLength.Value &&
                                  col.DefaultValue != null &&
                                  ((float)col.DefaultValue.Length / col.CharacterMaxLength) < (MinimumFill.Value / 100f)
                                  select col);

            foreach (var column in columnsToCheck)
            {
                var issue = new Issue(this, this.DefaultSeverity.Value);
                issue.Name                = "Inappropriate Length of Default Value For Char Column";
                issue.Context             = new ColumnContext(column);
                issue.Description         = new Description("Inappropriate length of default value for char column '{0}' in table {1}", column, column.Table);
                issue.ExtendedDescription = new Description("The maximum character length of this column is {0}, but the default value has a length of {1}. Consider using varchar to save space.", column.CharacterMaxLength, column.DefaultValue.Length);
                issueCollector.ReportIssue(issue);
            }
        }
예제 #29
0
        public override void Execute(DataTable table, IIssueCollector issueCollector, IProviderCollection providers)
        {
            var columns = table.Columns.Where(columnPredicate).Select(c => new StatCount {
                Column = c
            }).ToArray();

            using (var rowEnumerable = table.GetTableRowEnumerable())
                foreach (var row in rowEnumerable)
                {
                    foreach (var col in columns)
                    {
                        var val = row[col.Column.ColumnName];
                        if (val is DBNull || val.ToString().Equals(String.Empty))
                        {
                            continue;
                        }
                        var length = val.ToString().Length;
                        col.Items       += 1;
                        col.MaxLength    = Math.Max(col.MaxLength, length);
                        col.TotalLength += length;
                    }
                }
            foreach (var statCount in columns)
            {
                if (statCount.Items < this.MinRows.Value)
                {
                    continue;
                }
                var avgLength = statCount.TotalLength / statCount.Items;
                if (avgLength < statCount.Column.CharacterMaxLength * 0.6 && statCount.MaxLength < statCount.Column.CharacterMaxLength * 0.8)
                {
                    issueCollector.ReportIssue(new Issue(this, this.Severity)
                    {
                        Name        = "Large Text Column not Filled",
                        Context     = new TableContext(table),
                        Description = new Description("Column '{0}' contains on average {1} characters and the longest value has {2} characters. The maximum length of the column is declared to be {3} charaters", statCount.Column, avgLength, statCount.MaxLength, statCount.Column.CharacterMaxLength)
                    });
                }
            }
        }
예제 #30
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            this.BuildReservedWordList();
            var ignorePrimaryKeyNames = ((from table in database.Tables
                                          where table.PrimaryKey != null && table.PrimaryKey.PrimaryKeyName.ToLower() == "primary"
                                          select table).Count() == database.Tables.Where(p => p.PrimaryKey != null).Count());

            foreach (var schema in database.Schemas)
            {
                /*if (CheckString(schema.SchemaName))
                 *  issueCollector.ReportIssue(GetIssue(schema));*/

                foreach (var table in schema.Tables)
                {
                    if (CheckString(table.TableName))
                    {
                        issueCollector.ReportIssue(GetIssue(table));
                    }

                    foreach (var column in table.Columns)
                    {
                        if (CheckString(column.ColumnName))
                        {
                            issueCollector.ReportIssue(GetIssue(column));
                        }
                    }

                    if (!ignorePrimaryKeyNames && table.PrimaryKey != null)
                    {
                        if (CheckString(table.PrimaryKey.PrimaryKeyName))
                        {
                            issueCollector.ReportIssue(GetIssue(table.PrimaryKey));
                        }
                    }

                    foreach (var foreignKey in table.ForeignKeys)
                    {
                        if (CheckString(foreignKey.ForeignKeyName))
                        {
                            issueCollector.ReportIssue(GetIssue(foreignKey));
                        }
                    }
                }
            }
        }
예제 #31
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            foreach (var schema in database.Schemas)
            {
                if (!schema.Tables.Any(t => t.ForeignKeys.Count > 0))
                {
                    Issue s = new Issue(this, Severity.Critical);
                    s.Name        = "No Foreign Keys";
                    s.Description = new Description("The schema '{0}' has no foreign keys", schema.SchemaName);
                    s.Context     = new SchemaContext(schema);
                    issueCollector.ReportIssue(s);
                    continue;
                }

                DatabaseDictionary <TableID, Table> seenTables = DictionaryFactory.CreateTableID <Table>();
                DatabaseDictionary <TableID, Table> notSeen    = DictionaryFactory.CreateTableID <Table>();

                foreach (var t in schema.Tables)
                {
                    notSeen.Add(t, t);
                }
                List <List <Table> > clusters = new List <List <Table> >();
                while (notSeen.Count > 0)
                {
                    var table   = notSeen.First().Value;
                    var cluster = new List <Table>(schema.Tables.Count);
                    BrowseTables(table, seenTables, notSeen, cluster);
                    clusters.Add(cluster);
                }

                foreach (var cluster in clusters)
                {
                    if (cluster.Count == 1)
                    {
                        Issue issue = new Issue(this, this.DefaultSeverity.Value)
                        {
                            Context     = new TableContext(cluster[0]),
                            Name        = "Table Island",
                            Description = new Description("Table {0} does not reference anything and is not referenced by anything", cluster[0]),
                        };
                        issueCollector.ReportIssue(issue);
                    }
                    else
                    {
                        if (cluster.Count > schema.Tables.Count * this.MaxFractionTables.Value / 100f || schema.Tables.Count > this.MaxTableIslandCount.Value)
                        {
                            continue;
                        }

                        string tableList = String.Join(", ", cluster.Select(c => c.TableName));
                        if (tableList.Length > 20)
                        {
                            tableList = tableList.Substring(0, 20) + "...";
                        }

                        Issue issue = new Issue(this, LargeTableIslandSeverity.Value)
                        {
                            Context             = IssueContext.Create(cluster),
                            Name                = "Table Island",
                            Description         = new Description("There is a table island containing {0} tables: {1}", cluster.Count, tableList),
                            ExtendedDescription = new Description("Tables: {0}", cluster),
                        };
                        issueCollector.ReportIssue(issue);
                    }
                }
            }
        }
예제 #32
0
 public abstract void Execute(DataTable table, IProviderCollection providers);