예제 #1
0
        public override void Execute(Database database, IIssueCollector issueCollector, IProviderCollection providers)
        {
            this._nodeProps   = DictionaryFactory.CreateTableID <NodeProperties>();
            this._foundCycles = new List <List <Table> >();
            this._stack       = new Stack <Table>();
            this._index       = 0;
            foreach (var table in database.Tables)
            {
                if (!this._nodeProps.ContainsKey(table))
                {
                    this.Tarjan(table);
                }
            }

            foreach (var cycle in this._foundCycles)
            {
                var canInsert   = false;
                var foundTables = new Dictionary <Table, List <ForeignKey> >();
                foreach (var table in cycle)
                {
                    var fksValues = table.ForeignKeys.Where(p => cycle.Contains(p.PKTable)).ToList();
                    foundTables.Add(table, fksValues);
                    foreach (var fkValue in fksValues)
                    {
                        if (fkValue.ColumnPairs.All(f => f.FKColumn.IsNullable) ||
                            (fkValue.Deferrability == Deferrability.Deferrable && fkValue.InitialMode == InitialMode.InitiallyDeferred))
                        {
                            canInsert = true;
                        }
                    }
                }
                var issue = new Issue(this, this.DefaultSeverity.Value);
                issue.Name    = "Cycle Dependency Between Tables";
                issue.Context = IssueContext.Create(cycle);
                string tableList = String.Join(", ", cycle.Select(c => c.TableName));
                if (tableList.Length > 20)
                {
                    tableList = tableList.Substring(0, 20) + "...";
                }
                issue.Description = new Description("Cycle dependency between {0} tables: {1}", cycle.Count, tableList);
                var str = new StringBuilder();
                // Delete rules is no longer included in the check because of complex cycles
                if (!canInsert)
                {
                    str.Append("There is a cycle dependency, where the referential constraints could yield problems.");
                    str.Append("\n- Deferability and initially-deferred configurations could complicate insert, update and delete statements.");
                    issue.ExtendedDescription = new Description("{0}\n\nThe cycle contains the tables:\n\n{1}", str.ToString(), GetTable(foundTables));
                }
                else
                {
                    issue.Severity            = CycleWithoutDeferabilityProblems.Value;
                    issue.ExtendedDescription = new Description("There is a cyclic dependency, but there are no deferability constraints that could yield problems. Consider if the cyclic dependency is needed.\n\nThe cycle contains the tables:\n\n{0}", GetTable(foundTables));
                }
                issueCollector.ReportIssue(issue);
            }
        }
예제 #2
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);
                    }
                }
            }
        }
예제 #3
0
        public override void Finalize(Model.Database database, IProviderCollection providers)
        {
            var informationContent = providers.GetProvider <InformationContent>();
            var fks = database.Tables.SelectMany(t => t.ForeignKeys);

            DatabaseDictionary <TableID, List <JoinEdge> > dbJoinEdges = DictionaryFactory.CreateTableID <List <JoinEdge> >();
            DatabaseDictionary <TableID, double>           tableTotalEntropyTransfer = DictionaryFactory.CreateTableID <double>();

            foreach (var tbl in database.Tables)
            {
                dbJoinEdges[tbl] = new List <JoinEdge>(4);
                tableTotalEntropyTransfer[tbl] = 0;
            }

            foreach (var foreignKey in fks)
            {
                var pkColumns = (from cp in foreignKey.ColumnPairs
                                 select cp.PKColumn).ToArray();
                var fkColumns = (from cp in foreignKey.ColumnPairs
                                 select cp.FKColumn).ToArray();

                double fkEdgeEntropy;
                if (foreignKey.IsSingleColumn)
                {
                    fkEdgeEntropy = informationContent[foreignKey.FKColumn];
                }
                else
                {
                    fkEdgeEntropy = informationContent.GetMultiColumnEntropy((DataTable)foreignKey.FKTable, fkColumns);
                }

                var pkEdgeEntropy = Math.Log(Math.Max(foreignKey.PKTable.Cardinality, 1), 2); // Primary key guarantees uniqueness across pkcolumns, hence entropy equals log of cardinality.
                dbJoinEdges[foreignKey.PKTable].Add(new JoinEdge {
                    Table = foreignKey.FKTable, Columns = fkColumns, EdgeEntropy = fkEdgeEntropy
                });
                dbJoinEdges[foreignKey.FKTable].Add(new JoinEdge {
                    Table = foreignKey.PKTable, Columns = pkColumns, EdgeEntropy = pkEdgeEntropy
                });

                tableTotalEntropyTransfer[foreignKey.PKTable] += pkEdgeEntropy;
                tableTotalEntropyTransfer[foreignKey.FKTable] += fkEdgeEntropy;
            }

            DatabaseDictionary <TableID, DatabaseDictionary <TableID, double> > pmatrix = DictionaryFactory.CreateTableID <DatabaseDictionary <TableID, double> >();

            foreach (var tbl in database.Tables)
            {
                pmatrix[tbl] = DictionaryFactory.CreateTableID <double>();
            }

            foreach (var toTable in database.Tables)
            {
                var joinEdges = dbJoinEdges[toTable];
                foreach (var joinEdge in joinEdges)
                {
                    var fromTable               = joinEdge.Table;
                    var columnsEntropy          = joinEdge.EdgeEntropy;
                    var tableInformationContent = informationContent[fromTable];
                    var tableTotalTransfer      = tableTotalEntropyTransfer[fromTable];
                    var todic = pmatrix[toTable];
                    if (!todic.ContainsKey(fromTable))
                    {
                        todic[fromTable] = 0;
                    }

                    if (tableInformationContent + tableTotalTransfer > 0)
                    {
                        todic[fromTable] += columnsEntropy / (tableInformationContent + tableTotalTransfer);
                    }
                }
                var toTableRow = pmatrix[toTable];
            }

            foreach (var keyRow in pmatrix.Keys)
            {
                double selfLoopValue = 1d;
                foreach (var keyColumn in pmatrix.Keys)
                {
                    var row = pmatrix[keyColumn];
                    if (row.ContainsKey(keyRow))
                    {
                        selfLoopValue -= row[keyRow];
                    }
                }
                if (selfLoopValue < 0)
                {
                }
                pmatrix[keyRow][keyRow] = selfLoopValue;
            }


            DatabaseDictionary <TableID, double> importanceVector = DictionaryFactory.CreateTableID <double>();
            DatabaseDictionary <TableID, double> calculateVector  = DictionaryFactory.CreateTableID <double>();

            foreach (var table in database.Tables)
            {
                importanceVector[table] = Math.Max(informationContent[table], 0);
            }

            for (int i = 0; i < 100; i++)
            {
                foreach (var table in importanceVector.Keys)
                {
                    double newRank    = 0;
                    var    fromTables = pmatrix[table];
                    foreach (var fromTable in fromTables)
                    {
                        var fromRank = importanceVector[fromTable.Key];
                        newRank += fromRank * fromTable.Value;
                    }
                    calculateVector[table] = newRank;
                }

                {
                    var tmp = calculateVector;
                    calculateVector  = importanceVector;
                    importanceVector = tmp;
                }
            }

            var totalEntropy = importanceVector.Values.Sum();

            foreach (var k in importanceVector.Keys)
            {
                if (importanceVector[k] < 0)
                {
                }
                if (totalEntropy == 0)
                {
                    importanceVector[k] = 100f / database.Tables.Count;
                }
                else
                {
                    importanceVector[k] *= 100f / totalEntropy;
                }
            }
            this._importanceVector = importanceVector;
        }
예제 #4
0
        public override void Execute(Database database, IProviderCollection providers)
        {
            double damping = 0.85;

            DatabaseDictionary <TableID, DoubleWrapper> ranks          = DictionaryFactory.CreateTableID <DoubleWrapper>();
            DatabaseDictionary <TableID, DoubleWrapper> rankCalculator = DictionaryFactory.CreateTableID <DoubleWrapper>();
            DatabaseDictionary <TableID, Table[]>       neighborMatrix = DictionaryFactory.CreateTableID <Table[]>();

            var initialRank = 1f / database.Tables.Count;

            foreach (var table in database.Tables)
            {
                ranks.Add(table, new DoubleWrapper {
                    Value = 1
                });
                var referencedBy = new List <Table>();
                foreach (var fkTable in table.ReferencedBy)
                {
                    foreach (var foreignKey in fkTable.ForeignKeys)
                    {
                        if (foreignKey.PKTable.Equals(table))
                        {
                            referencedBy.Add(fkTable);
                        }
                    }
                }
                neighborMatrix.Add(table, referencedBy.ToArray());
            }

            foreach (var tableID in ranks.Keys)
            {
                rankCalculator[tableID] = new DoubleWrapper {
                    Value = 0
                };
                ranks[tableID] = new DoubleWrapper {
                    Value = 0
                };
            }

            for (int i = 0; i < 100; i++)
            {
                double error = 0;
                foreach (var tableID in ranks.Keys)
                {
                    double value      = 0;
                    var    references = neighborMatrix[tableID];
                    foreach (var reference in references)
                    {
                        var referenceRank = ranks[reference];
                        value += referenceRank.Value / reference.ForeignKeys.Count;
                    }
                    double newRank;
                    rankCalculator[tableID].Value = newRank = value * damping + initialRank * (1 - damping);
                    error += Math.Abs(ranks[tableID].Value - newRank);
                }

                {
                    var tmp = rankCalculator;
                    rankCalculator = ranks;
                    ranks          = tmp;
                }

                if (error < 0.001)
                {
                    break;
                }
            }

            double sum = 0;

            foreach (var key in ranks.Keys)
            {
                sum += ranks[key].Value;
            }

            foreach (var key in ranks.Keys)
            {
                _ranks[key] = ranks[key].Value / sum * 100;
            }
        }
예제 #5
0
        public static Database DatabaseFactory(Extractor extractor, IEnumerable <DBLint.DataAccess.DBObjects.Schema> selectedSchemas, IEnumerable <DBLint.DataAccess.DBObjects.TableID> ignoredTables)
        {
            var database          = new Database(extractor.DatabaseName, extractor.Database);
            var ignoredDictionary = DictionaryFactory.CreateTableID <TableID>();

            foreach (var ignoredTable in ignoredTables)
            {
                var tblid = new TableID(extractor.DatabaseName, ignoredTable.SchemaName, ignoredTable.TableName);
                ignoredDictionary.Add(tblid, tblid);
            }

            using (var db = database)
            {
                var dbSchemas = extractor.Database.GetSchemas();
                foreach (var dbSchema in dbSchemas)
                {
                    using (var schema = new Schema(db.DatabaseName, dbSchema.SchemaName))
                    {
                        if (!selectedSchemas.Any(p => p.Equals(dbSchema)))
                        {
                            continue;
                        }
                        schema.Database = db;
                        db._schemas.Add(schema);

                        #region Table and table columns

                        var dbTables = extractor.Database.GetTables(schema.SchemaName);
                        var tables   = from dbTable in dbTables
                                       orderby dbTable.TableName
                                       select dbTable;

                        foreach (var dbTable in tables)
                        {
                            var table = new DataTable(db.DatabaseName, schema.SchemaName, dbTable.TableName, extractor.Database);

                            if (ignoredDictionary.ContainsKey(table))
                            {
                                database.IgnoredTables.Add(table);
                                continue;
                            }

                            schema._tables.Add(table);
                            db.tableDictionary.Add(table, table);
                            table.Database = db;
                            table.Schema   = schema;
                        }

                        var dbColumns = extractor.Database.GetColumns(schema.SchemaName);

                        var columnID = new ColumnID(extractor.DatabaseName, schema.SchemaName, null, null);
                        foreach (var dbColumn in dbColumns)
                        {
                            columnID.TableName  = dbColumn.TableName;
                            columnID.ColumnName = dbColumn.ColumnName;
                            if (db.tableDictionary.ContainsKey(columnID))
                            {
                                var column = new Column(db.DatabaseName, schema.SchemaName, dbColumn.TableName, dbColumn.ColumnName);
                                var table  = db.tableDictionary[column];
                                table._columns.Add(column);
                                column.DataType           = dbColumn.DataType;
                                column.DefaultValue       = dbColumn.DefaultValue;
                                column.OrdinalPosition    = dbColumn.OrdinalPosition;
                                column.CharacterMaxLength = dbColumn.CharacterMaxLength;
                                column.IsNullable         = dbColumn.IsNullable;
                                column.NumericPrecision   = dbColumn.NumericPrecision;
                                column.NumericScale       = dbColumn.NumericScale;
                                column.Table      = table;
                                column.Schema     = schema;
                                column.Database   = db;
                                column.IsSequence = dbColumn.IsSequence;
                                column.IsDefaultValueAFunction = dbColumn.DefaultIsFunction;
                            }
                        }

                        #endregion

                        #region Views and view columns

                        var dbViews = extractor.Database.GetViews(schema.SchemaName);
                        var views   = from dbView in dbViews
                                      orderby dbView.ViewName
                                      select dbView;

                        foreach (var dbView in views)
                        {
                            var view = new View(db.DatabaseName, schema.SchemaName, dbView.ViewName);

                            schema._views.Add(view);
                            db.viewDictionary.Add(view, view);
                            view.Database = db;
                            view.Schema   = schema;
                        }

                        var dbViewColumns = extractor.Database.GetViewColumns(schema.SchemaName);
                        var viewColumnID  = new ViewColumnID(extractor.DatabaseName, schema.SchemaName, null, null);

                        foreach (var dbViewColumn in dbViewColumns)
                        {
                            viewColumnID.ViewName   = dbViewColumn.ViewName;
                            viewColumnID.ColumnName = dbViewColumn.ColumnName;

                            if (db.viewDictionary.ContainsKey(viewColumnID))
                            {
                                var viewColumn = new ViewColumn(db.DatabaseName, schema.SchemaName, dbViewColumn.ViewName, dbViewColumn.ColumnName);
                                var view       = db.viewDictionary[viewColumn];
                                view._columns.Add(viewColumn);
                                viewColumn.Database           = db;
                                viewColumn.Schema             = schema;
                                viewColumn.View               = view;
                                viewColumn.DataType           = dbViewColumn.DataType;
                                viewColumn.DefaultValue       = dbViewColumn.DefaultValue;
                                viewColumn.OrdinalPosition    = dbViewColumn.OrdinalPosition;
                                viewColumn.CharacterMaxLength = dbViewColumn.CharacterMaxLength;
                                viewColumn.IsNullable         = dbViewColumn.IsNullable;
                                viewColumn.NumericPrecision   = dbViewColumn.NumericPrecision;
                                viewColumn.NumericScale       = dbViewColumn.NumericScale;
                                viewColumn.Privileges         = dbViewColumn.Privileges;
                            }
                        }

                        #endregion

                        // Adding functions
                        var functions = extractor.Database.GetFunctions(schema.SchemaName);
                        foreach (var function in functions)
                        {
                            var f = new Function(
                                database.DatabaseName,
                                function.SchemaName,
                                function.RoutineName);
                            f.Database = database;
                            f.Schema   = schema;

                            schema._functions.Add(f);
                        }

                        var fParameters = extractor.Database.GetFunctionsParameters(schema.SchemaName);
                        foreach (var fParameter in fParameters)
                        {
                            var fp = new Parameter(database.DatabaseName, fParameter.SchemaName, fParameter.RoutineName, fParameter.ParameterName);
                            fp.Database = schema.Database;
                            fp.Schema   = schema;

                            fp.DataType           = fParameter.DataType;
                            fp.Direction          = fParameter.Direction;
                            fp.CharacterMaxLength = fParameter.CharacterMaxLength;
                            fp.NumericPrecision   = fParameter.NumericPrecision;
                            fp.NumericScale       = fParameter.NumericScale;
                            fp.OrdinalPosition    = fParameter.OrdinalPosition;

                            var tmpF = schema._functions.Where(f => f.FunctionName.Equals(fp.RoutineName)).FirstOrDefault();
                            if (tmpF != null)
                            {
                                fp.Routine = tmpF;
                                tmpF._parameters.Add(fp);
                            }
                        }

                        // Adding stored procedures
                        var storedProcedures = extractor.Database.GetStoredProcedures(schema.SchemaName);
                        foreach (var storedProcedure in storedProcedures)
                        {
                            var sp = new StoredProcedure(
                                database.DatabaseName,
                                storedProcedure.SchemaName,
                                storedProcedure.RoutineName);

                            sp.Database = database;
                            sp.Schema   = schema;

                            schema._storedProcedures.Add(sp);
                        }

                        var parameters = extractor.Database.GetStoredProceduresParameters(schema.SchemaName);
                        foreach (var parameter in parameters)
                        {
                            var p = new Parameter(database.DatabaseName, parameter.SchemaName, parameter.RoutineName, parameter.ParameterName);
                            p.Database = schema.Database;
                            p.Schema   = schema;

                            p.DataType           = parameter.DataType;
                            p.Direction          = parameter.Direction;
                            p.CharacterMaxLength = parameter.CharacterMaxLength;
                            p.NumericPrecision   = parameter.NumericPrecision;
                            p.NumericScale       = parameter.NumericScale;
                            p.OrdinalPosition    = parameter.OrdinalPosition;

                            var tmpSp = schema._storedProcedures.Where(sp => sp.StoredProcedureName.Equals(p.RoutineName)).FirstOrDefault();
                            if (tmpSp != null)
                            {
                                p.Routine = tmpSp;
                                tmpSp._parameters.Add(p);
                            }
                        }
                    }
                }
            }
            AddForeignKeys(extractor, database);
            AddPrimaryKeys(extractor, database);
            AddIndices(extractor, database);
            AddUniqueConstraints(extractor, database);

            foreach (var tbl in database.Tables)
            {
                tbl.Dispose();
            }

            foreach (var view in database.Views)
            {
                view.Dispose();
            }

            AddCardinalities(database.tableDictionary, extractor, selectedSchemas);

            database.Escaper = Escaper.GetEscaper(extractor.Database.DBMS);
            database.DBMS    = extractor.Database.DBMS;
            return(database);
        }