using System; using System.Collections.Generic; using System.Linq; using SyncEngine.Configuration; namespace SyncEngine.SqlServer { public static class SqlSchemaKeyBuilder { public static bool ShouldSkipIndex(AccessIndexInfo index) { if (index == null || index.Columns == null || index.Columns.Count == 0) { return true; } return index.Columns.Any(IsSyncColumn); } public static string BuildPrimaryKeyConstraintName(string tableName) { var name = "PK_" + SqlIdentifierHelper.SanitizeConstraintName(tableName); return TruncateIdentifier(name); } public static string BuildSqlIndexName(AccessIndexInfo index) { var prefix = index.IsPrimary ? "PK" : index.IsUnique ? "UQ" : "IX"; var baseName = prefix + "_" + SqlIdentifierHelper.SanitizeConstraintName(index.TableName) + "_" + string.Join("_", index.Columns.Select(SqlIdentifierHelper.SanitizeConstraintName)); if (!index.IsPrimary && !string.IsNullOrWhiteSpace(index.IndexName)) { baseName = prefix + "_" + SqlIdentifierHelper.SanitizeConstraintName(index.TableName) + "_" + SqlIdentifierHelper.SanitizeConstraintName(index.IndexName); } return TruncateIdentifier(baseName); } public static string BuildPrimaryKeyAlterSql(string qualifiedTable, string constraintName, IList columns) { return string.Format( "ALTER TABLE {0} ADD CONSTRAINT [{1}] PRIMARY KEY CLUSTERED ({2})", qualifiedTable, constraintName, FormatColumnList(columns)); } public static string BuildCreateIndexSql( string qualifiedTable, string indexName, IList columns, bool unique, string filterClause = null) { var uniqueKeyword = unique ? "UNIQUE " : string.Empty; var filter = string.IsNullOrWhiteSpace(filterClause) ? string.Empty : " " + filterClause; return string.Format( "CREATE {0}NONCLUSTERED INDEX [{1}] ON {2} ({3}){4}", uniqueKeyword, indexName, qualifiedTable, FormatColumnList(columns), filter); } /// /// Access allows multiple NULLs in unique fields; SQL Server unique indexes treat NULL as equal. /// A filtered unique index matches Access semantics for single nullable columns. /// public static string BuildNullableUniqueFilter(IList columns) { if (columns == null || columns.Count != 1) { return null; } return "WHERE [" + columns[0] + "] IS NOT NULL"; } public static string FormatColumnList(IEnumerable columns) { return string.Join(", ", columns.Select(c => "[" + c + "]")); } public static string NormalizeColumnKey(IEnumerable columns) { return string.Join("|", columns.Select(c => c.ToUpperInvariant())); } private static bool IsSyncColumn(string columnName) { return columnName != null && columnName.StartsWith("_sync_", StringComparison.OrdinalIgnoreCase); } private static string TruncateIdentifier(string name) { if (name.Length <= 128) { return name; } return name.Substring(0, 128); } } }