示例#1
0
 public ColumnRelationship(IColumn fromColumn, IColumn toColumn, RelationshipOrigin relationshipOrigin)
 {
     FromColumn         = fromColumn;
     Identifier         = $"{fromColumn.MultiPartIdentifier}.{toColumn.MultiPartIdentifier}";
     ToColumn           = toColumn;
     RelationshipOrigin = relationshipOrigin;
 }
示例#2
0
 public TableRelationship(IReadOnlyDictionary <string, IMetadataIdentifier> metadataIdentifierByMultiPartIdentifier, string fromTableMultiPartIdentifier, string toTableMultiPartIdentifier, RelationshipOrigin relationshipOrigin)
 {
     FromTable          = (ITable)metadataIdentifierByMultiPartIdentifier[fromTableMultiPartIdentifier];
     ToTable            = (ITable)metadataIdentifierByMultiPartIdentifier[toTableMultiPartIdentifier];
     Source             = fromTableMultiPartIdentifier;
     Target             = toTableMultiPartIdentifier;
     RelationshipOrigin = relationshipOrigin;
 }
        public IEnumerable <(IColumn FromColumn, IColumn ToColumn, RelationshipOrigin RelationshipOrigin)> GetColumnRelationshipsWithSqlModuleDefinition(IEnumerable <IServer> servers, RelationshipOrigin relationshipOrigin)
        {
            foreach (var server in servers)
            {
                foreach (var database in server.Databases)
                {
                    using (var sqlConnection = new SqlConnection($"Data Source={server.ServerName};Initial Catalog={database.DatabaseName};Integrated Security=true"))
                    {
                        IEnumerable <string> sqlModuleDefinitions;

                        try
                        {
                            sqlModuleDefinitions = sqlConnection.Query <string>(@"
                            SELECT SM.DEFINITION AS SqlModuleDefinition
                            FROM SYS.OBJECTS O
                            INNER JOIN SYS.SQL_MODULES SM ON O.OBJECT_ID = SM.OBJECT_ID;
                            ");
                        }
                        catch (Exception)
                        {
                            yield break;
                        }

                        foreach (var sqlModuleDefinition in sqlModuleDefinitions)
                        {
                            foreach (var columnRelationship in GetColumnRelationshipsByChangeScriptDefinition(sqlModuleDefinition, server.ServerName, database.DatabaseName, relationshipOrigin))
                            {
                                yield return(columnRelationship.FromColumn, columnRelationship.ToColumn, relationshipOrigin);
                            }
                        }
                    }
                }
            }
        }
        public IEnumerable <(IColumn FromColumn, IColumn ToColumn, RelationshipOrigin RelationshipOrigin)> GetColumnRelationshipsWithChangeScriptReference(string dataDirectoryPath, RelationshipOrigin relationshipOrigin)
        {
            var dataDirectoryUri = new Uri(dataDirectoryPath);

            if (!Directory.Exists(dataDirectoryUri.LocalPath))
            {
                yield break;
            }

            var repositoryPath = Repository.Discover(dataDirectoryPath);

            if (string.IsNullOrEmpty(repositoryPath))
            {
                yield break;
            }

            using (var repository = new Repository(repositoryPath))
            {
                var contextualServerName = dataDirectoryUri.Host.ToLower();
                var head = repository.Head;
                var tip  = head.Tip;
                var tree = tip.Tree;

                foreach (var databaseNameWithFileContent in GetDatabaseNameWithFileContent(contextualServerName, tree))
                {
                    var transactSqlText = databaseNameWithFileContent.FileContent;
                    var databaseName    = databaseNameWithFileContent.DatabaseName;

                    foreach (var columnRelationship in GetColumnRelationshipsByChangeScriptDefinition(transactSqlText, contextualServerName, databaseName, relationshipOrigin))
                    {
                        yield return(columnRelationship.FromColumn, columnRelationship.ToColumn, relationshipOrigin);
                    }
                }
            }
        }
        public IEnumerable <(IColumn FromColumn, IColumn ToColumn, RelationshipOrigin RelationshipOrigin)> GetColumnRelationshipsWithKeyReferenceDefinition(IEnumerable <IServer> servers, RelationshipOrigin relationshipOrigin)
        {
            foreach (var server in servers)
            {
                foreach (var database in server.Databases)
                {
                    using (var sqlConnection = new SqlConnection($"Data Source={server.ServerName};Initial Catalog={database.DatabaseName};Integrated Security=true"))
                    {
                        IEnumerable <dynamic> keyReferenceDefinitions;

                        try
                        {
                            keyReferenceDefinitions = sqlConnection.Query(@"
                            WITH ObjectExpression
                            AS (
                                SELECT @@SERVERNAME                      AS ServerName
                                     , DB_NAME()                         AS DatabaseName
                                     , ISC.TABLE_SCHEMA                  AS SchemaName
                                     , O.NAME                            AS TableName
                                     , ISC.COLUMN_NAME                   AS ColumnName
                                     , O.OBJECT_ID                       AS TableIdentifier
                                     , C.COLUMN_ID                       AS ColumnIdentifier
                                FROM SYS.OBJECTS O
                                INNER JOIN INFORMATION_SCHEMA.COLUMNS AS ISC ON SCHEMA_NAME(O.SCHEMA_ID) = ISC.TABLE_SCHEMA AND O.NAME = ISC.TABLE_NAME
                                INNER JOIN SYS.COLUMNS AS C                  ON O.OBJECT_ID = C.OBJECT_ID                   AND ISC.COLUMN_NAME = C.NAME
                                ), ColumnRelationshipExpression
                            AS (
                                SELECT ObjectExpressionFrom.ServerName   AS FromServerName
                                     , ObjectExpressionFrom.DatabaseName AS FromDatabaseName
                                     , ObjectExpressionFrom.SchemaName   AS FromSchemaName
                                     , ObjectExpressionFrom.TableName    AS FromTableName
                                     , ObjectExpressionFrom.ColumnName   AS FromColumnName
                                     , ObjectExpressionTo.ServerName     AS ToServerName
                                     , ObjectExpressionTo.DatabaseName   AS ToDatabaseName
                                     , ObjectExpressionTo.SchemaName     AS ToSchemaName
                                     , ObjectExpressionTo.TableName      AS ToTableName
                                     , ObjectExpressionTo.ColumnName     AS ToColumnName
                                FROM SYS.FOREIGN_KEY_COLUMNS AS FKC
                                INNER JOIN ObjectExpression AS ObjectExpressionFrom ON FKC.PARENT_OBJECT_ID     = ObjectExpressionFrom.TableIdentifier AND ObjectExpressionFrom.ColumnIdentifier = FKC.PARENT_COLUMN_ID
                                INNER JOIN ObjectExpression AS ObjectExpressionTo   ON FKC.REFERENCED_OBJECT_ID = ObjectExpressionTo.TableIdentifier   AND ObjectExpressionTo.ColumnIdentifier   = FKC.REFERENCED_COLUMN_ID
                                )
                            SELECT LOWER(CONCAT(FromServerName, '.', FromDatabaseName, '.', FromSchemaName, '.', FromTableName, '.', FromColumnName, '.',
                                                ToServerName,   '.', ToDatabaseName,   '.', ToSchemaName,   '.', ToTableName,   '.', ToColumnName))   AS Identifier
                                 , LOWER(CONCAT(FromServerName, '.', FromDatabaseName, '.', FromSchemaName, '.', FromTableName, '.', FromColumnName)) AS FromColumnMultiPartIdentifier
                                 , LOWER(CONCAT(ToServerName,   '.', ToDatabaseName,   '.', ToSchemaName,   '.', ToTableName,   '.', ToColumnName))   AS ToColumnMultiPartIdentifier
                            FROM ColumnRelationshipExpression
                            ORDER BY FromColumnMultiPartIdentifier
                                   , ToColumnMultiPartIdentifier
                            ");
                        }
                        catch (Exception)
                        {
                            yield break;
                        }

                        foreach (var keyReferenceDefinition in keyReferenceDefinitions)
                        {
                            var fromColumn = _metadataIdentifierByMultiPartIdentifier[keyReferenceDefinition.FromColumnMultiPartIdentifier];
                            var toColumn   = _metadataIdentifierByMultiPartIdentifier[keyReferenceDefinition.ToColumnMultiPartIdentifier];

                            yield return(fromColumn, toColumn, relationshipOrigin);
                        }
                    }
                }
            }
        }
 public IEnumerable <(IColumn FromColumn, IColumn ToColumn, RelationshipOrigin RelationshipOrigin)> GetColumnRelationshipsByDatabaseStructuralCloneReference(IEnumerable <IServer> servers, RelationshipOrigin relationshipOrigin)
 {
     yield break;
 }
        public IEnumerable <IColumnRelationship> ParseBooleanComparisonExpression(BooleanComparisonExpression booleanComparisonExpression, IDictionary <string, ITable> tableByAliasIdentifier, IList <int> booleanComparisonExpressionIdentifiers, RelationshipOrigin relationshipOrigin)
        {
            if (booleanComparisonExpression.ComparisonType == BooleanComparisonType.NotEqualToBrackets || booleanComparisonExpression.ComparisonType == BooleanComparisonType.NotEqualToExclamation)
            {
                yield break;
            }

            var columnReferenceExpressions = _visitorProvider.GetColumnReferenceExpressions(booleanComparisonExpression).AsList();

            if (columnReferenceExpressions.Count != 2)
            {
                yield break;
            }

            var fromColumnReferenceExpression = columnReferenceExpressions[0];

            if (!TryParseColumn(fromColumnReferenceExpression, tableByAliasIdentifier, out IColumn fromColumn))
            {
                yield break;
            }

            var toColumnReferenceExpression = columnReferenceExpressions[1];

            if (!TryParseColumn(toColumnReferenceExpression, tableByAliasIdentifier, out IColumn toColumn))
            {
                yield break;
            }

            var booleanComparisonExpressionIdentifier = booleanComparisonExpression.FirstTokenIndex + booleanComparisonExpression.LastTokenIndex;

            if (booleanComparisonExpressionIdentifiers.Contains(booleanComparisonExpressionIdentifier))
            {
                yield break;
            }

            booleanComparisonExpressionIdentifiers.Add(booleanComparisonExpressionIdentifier);

            var columnRelationship = new ColumnRelationship(fromColumn, toColumn, relationshipOrigin);

            yield return(columnRelationship);
        }
        public IEnumerable <IColumnRelationship> ParseViewTableColumnToBaseTableColumnRelationships(TSqlStatement tsqlStatement, string contextualServerName, string contextualDatabaseName, RelationshipOrigin relationshipOrigin)
        {
            var viewStatementBody = tsqlStatement as ViewStatementBody;

            if (viewStatementBody == null)
            {
                yield break;
            }

            if (!TryParseTable(contextualServerName, contextualDatabaseName, viewStatementBody.SchemaObjectName, out ITable viewTable))
            {
                yield break;
            }

            var selectStatement    = viewStatementBody.SelectStatement;
            var queryExpression    = selectStatement.QueryExpression;
            var querySpecification = queryExpression as QuerySpecification;

            if (!(queryExpression is QuerySpecification))
            {
                yield break;
            }

            var selectElements = querySpecification.SelectElements;

            if (viewTable.Columns.Count != selectElements.Count)
            {
                yield break;
            }

            var viewStatementFromClause = querySpecification.FromClause;

            if (!TryParseTableByAliasIdentifier(viewStatementFromClause, contextualServerName, contextualDatabaseName, out IDictionary <string, ITable> viewTableByAliasIdentifier))
            {
                yield break;
            }

            for (var index = 0; index < selectElements.Count; index++)
            {
                var selectElement             = selectElements[index];
                var selectScalarExpression    = (SelectScalarExpression)selectElement;
                var scalarExpression          = selectScalarExpression.Expression;
                var columnReferenceExpression = scalarExpression as ColumnReferenceExpression;

                if (!(scalarExpression is ColumnReferenceExpression))
                {
                    continue;
                }

                var viewColumns     = viewTable.Columns.AsList();
                var viewTableColumn = viewColumns[index];

                if (!TryParseColumn(columnReferenceExpression, viewTableByAliasIdentifier, out IColumn baseTableColumn))
                {
                    continue;
                }

                var columnRelationship = new ColumnRelationship(viewTableColumn, baseTableColumn, relationshipOrigin);

                yield return(columnRelationship);
            }
        }
        public IEnumerable <IColumnRelationship> ParseFromClauseRelationships(TSqlStatement tsqlStatement, string contextualServerName, string contextualDatabaseName, IList <int> booleanComparisonExpressionIdentifiers, RelationshipOrigin relationshipOrigin)
        {
            foreach (var fromClause in _visitorProvider.GetFromClauses(tsqlStatement))
            {
                if (!IsParsableFromClause(fromClause))
                {
                    continue;
                }

                if (!TryParseTableByAliasIdentifier(fromClause, contextualServerName, contextualDatabaseName, out IDictionary <string, ITable> tableByAliasIdentifier))
                {
                    continue;
                }

                foreach (var booleanComparisonExpression in _visitorProvider.GetBooleanComparisonExpressions(fromClause))
                {
                    foreach (var columnRelationship in ParseBooleanComparisonExpression(booleanComparisonExpression, tableByAliasIdentifier, booleanComparisonExpressionIdentifiers, relationshipOrigin))
                    {
                        if (columnRelationship.FromColumn.Table.MultiPartIdentifier == columnRelationship.ToColumn.Table.MultiPartIdentifier)
                        {
                            continue;
                        }

                        yield return(columnRelationship);
                    }
                }
            }
        }
        public IEnumerable <IColumnRelationship> GetColumnRelationshipsByChangeScriptDefinition(string sql, string contextualServerName, string contextualDatabaseName, RelationshipOrigin relationshipOrigin)
        {
            sql = sql.ToLower();
            contextualServerName   = contextualServerName.ToLower();
            contextualDatabaseName = contextualDatabaseName.ToLower();

            var tsqlScript = (TSqlScript)_sqlParserFacade.Parse(sql, out IList <ParseError> parseErrors);

            if (parseErrors.Any())
            {
                yield break;
            }

            var booleanComparisonExpressionIdentifiers = new List <int>();

            foreach (var tsqlBatch in tsqlScript.Batches)
            {
                for (var index = 0; index < tsqlBatch.Statements.Count; index++)
                {
                    var tsqlStatement = tsqlBatch.Statements[index];

                    switch (tsqlStatement)
                    {
                    case PrintStatement printStatement:
                        continue;

                    case ExecuteStatement executeStatement:
                        foreach (var literal in _visitorProvider.GetLiteral(executeStatement))
                        {
                            if (literal.LiteralType != LiteralType.String)
                            {
                                continue;
                            }

                            var nestedTSqlScript = (TSqlScript)_sqlParserFacade.Parse(literal.Value, out IList <ParseError> nestedParseErrors);

                            if (nestedParseErrors.Any())
                            {
                                continue;
                            }

                            foreach (var nestedTSqlBatch in nestedTSqlScript.Batches)
                            {
                                foreach (var nestedTsqlStatements in nestedTSqlBatch.Statements)
                                {
                                    tsqlBatch.Statements.Insert(index + 1, nestedTsqlStatements);
                                }
                            }
                        }
                        break;

                    case UseStatement useStatement:
                        var usingDatabaseName = useStatement.DatabaseName.Value.ToLower();

                        if (usingDatabaseName != "master" && usingDatabaseName != contextualDatabaseName)
                        {
                            contextualDatabaseName = usingDatabaseName;
                        }
                        continue;
                    }

                    foreach (var columnRelationship in ParseFromClauseRelationships(tsqlStatement, contextualServerName, contextualDatabaseName, booleanComparisonExpressionIdentifiers, relationshipOrigin))
                    {
                        yield return(columnRelationship);
                    }

                    foreach (var columnRelationship in ParseViewTableColumnToBaseTableColumnRelationships(tsqlStatement, contextualServerName, contextualDatabaseName, relationshipOrigin))
                    {
                        yield return(columnRelationship);
                    }
                }
            }
        }