From 29ebb42a014b5728023ff9d1c6cf1e252c186bb4 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 27 Jul 2021 10:41:46 -0600 Subject: [PATCH] Fixes ugly classes not structured correctly and removes dead code, simplifies how db types are initialized and removes hacks. Fixes datetimeoffset definition. --- .../Persistence/SqlSyntax/DbTypes.cs | 25 ++--- .../Persistence/SqlSyntax/DbTypesFactory.cs | 20 ++++ .../MicrosoftSqlSyntaxProviderBase.cs | 4 +- .../SqlSyntax/SqlSyntaxProviderBase.cs | 104 +++++++++--------- .../SqlCeSyntaxProvider.cs | 8 +- 5 files changed, 87 insertions(+), 74 deletions(-) create mode 100644 src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypesFactory.cs diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypes.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypes.cs index 004c4f11f4..18e4791d0b 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypes.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypes.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Data; @@ -6,24 +6,13 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax { public class DbTypes { - public DbType DbType; - public string TextDefinition; - public bool ShouldQuoteValue; - public Dictionary ColumnTypeMap = new Dictionary(); - public Dictionary ColumnDbTypeMap = new Dictionary(); - - public void Set(DbType dbType, string fieldDefinition) + public DbTypes(IReadOnlyDictionary columnTypeMap, IReadOnlyDictionary columnDbTypeMap) { - DbType = dbType; - TextDefinition = fieldDefinition; - ShouldQuoteValue = fieldDefinition != "INTEGER" - && fieldDefinition != "BIGINT" - && fieldDefinition != "DOUBLE" - && fieldDefinition != "DECIMAL" - && fieldDefinition != "BOOL"; - - ColumnTypeMap[typeof(T)] = fieldDefinition; - ColumnDbTypeMap[typeof(T)] = dbType; + ColumnTypeMap = columnTypeMap; + ColumnDbTypeMap = columnDbTypeMap; } + + public IReadOnlyDictionary ColumnTypeMap { get; } + public IReadOnlyDictionary ColumnDbTypeMap { get; } } } diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypesFactory.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypesFactory.cs new file mode 100644 index 0000000000..bf1e0989f5 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypesFactory.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Data; + +namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax +{ + internal class DbTypesFactory + { + private readonly Dictionary _columnTypeMap = new Dictionary(); + private readonly Dictionary _columnDbTypeMap = new Dictionary(); + + public void Set(DbType dbType, string fieldDefinition) + { + _columnTypeMap[typeof(T)] = fieldDefinition; + _columnDbTypeMap[typeof(T)] = dbType; + } + + public DbTypes Create() => new DbTypes(_columnTypeMap, _columnDbTypeMap); + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs index 4c75128926..0093ee14ce 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/MicrosoftSqlSyntaxProviderBase.cs @@ -22,8 +22,6 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax DecimalColumnDefinition = "DECIMAL(38,6)"; TimeColumnDefinition = "TIME"; //SQLSERVER 2008+ BlobColumnDefinition = "VARBINARY(MAX)"; - - InitColumnTypeMap(); } public override string RenameTable => "sp_rename '{0}', '{1}'"; @@ -78,7 +76,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax /// public virtual SqlDbType GetSqlDbType(Type clrType) { - var dbType = DbTypeMap.ColumnDbTypeMap.First(x => x.Key == clrType).Value; + var dbType = DbTypeMap.ColumnDbTypeMap[clrType]; return GetSqlDbType(dbType); } diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs index 20cbb689c1..753a372e82 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlSyntaxProviderBase.cs @@ -24,6 +24,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax public abstract class SqlSyntaxProviderBase : ISqlSyntaxProvider where TSyntax : ISqlSyntaxProvider { + private readonly Lazy _dbTypes; + protected SqlSyntaxProviderBase() { ClauseOrder = new List> @@ -42,14 +44,14 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax StringColumnDefinition = string.Format(StringLengthColumnDefinitionFormat, DefaultStringLength); DecimalColumnDefinition = string.Format(DecimalColumnDefinitionFormat, DefaultDecimalPrecision, DefaultDecimalScale); - InitColumnTypeMap(); - // ReSharper disable VirtualMemberCallInConstructor // ok to call virtual GetQuotedXxxName here - they don't depend on any state var col = Regex.Escape(GetQuotedColumnName("column")).Replace("column", @"\w+"); var fld = Regex.Escape(GetQuotedTableName("table") + ".").Replace("table", @"\w+") + col; // ReSharper restore VirtualMemberCallInConstructor AliasRegex = new Regex("(" + fld + @")\s+AS\s+(" + col + ")", RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled); + + _dbTypes = new Lazy(InitColumnTypeMap); } public Regex AliasRegex { get; } @@ -70,64 +72,68 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax public string StringLengthColumnDefinitionFormat { get; } public string AutoIncrementDefinition { get; protected set; } = "AUTOINCREMENT"; - public string IntColumnDefinition { get; } = "INTEGER"; - public string LongColumnDefinition { get; } = "BIGINT"; + public string IntColumnDefinition { get; protected set; } = "INTEGER"; + public string LongColumnDefinition { get; protected set; } = "BIGINT"; public string GuidColumnDefinition { get; protected set; } = "GUID"; public string BoolColumnDefinition { get; protected set; } = "BOOL"; public string RealColumnDefinition { get; protected set; } = "DOUBLE"; public string DecimalColumnDefinition { get; protected set; } public string BlobColumnDefinition { get; protected set; } = "BLOB"; - public string DateTimeColumnDefinition { get; } = "DATETIME"; + public string DateTimeColumnDefinition { get; protected set; } = "DATETIME"; + public string DateTimeOffsetColumnDefinition { get; protected set; } = "DATETIMEOFFSET(7)"; public string TimeColumnDefinition { get; protected set; } = "DATETIME"; protected IList> ClauseOrder { get; } - protected DbTypes DbTypeMap { get; } = new DbTypes(); + protected DbTypes DbTypeMap => _dbTypes.Value; - protected void InitColumnTypeMap() + private DbTypes InitColumnTypeMap() { - DbTypeMap.Set(DbType.String, StringColumnDefinition); - DbTypeMap.Set(DbType.StringFixedLength, StringColumnDefinition); - DbTypeMap.Set(DbType.StringFixedLength, StringColumnDefinition); - DbTypeMap.Set(DbType.String, StringColumnDefinition); - DbTypeMap.Set(DbType.Boolean, BoolColumnDefinition); - DbTypeMap.Set(DbType.Boolean, BoolColumnDefinition); - DbTypeMap.Set(DbType.Guid, GuidColumnDefinition); - DbTypeMap.Set(DbType.Guid, GuidColumnDefinition); - DbTypeMap.Set(DbType.DateTime, DateTimeColumnDefinition); - DbTypeMap.Set(DbType.DateTime, DateTimeColumnDefinition); - DbTypeMap.Set(DbType.Time, TimeColumnDefinition); - DbTypeMap.Set(DbType.Time, TimeColumnDefinition); - DbTypeMap.Set(DbType.DateTimeOffset, TimeColumnDefinition); - DbTypeMap.Set(DbType.DateTimeOffset, TimeColumnDefinition); + var dbTypeMap = new DbTypesFactory(); + dbTypeMap.Set(DbType.String, StringColumnDefinition); + dbTypeMap.Set(DbType.StringFixedLength, StringColumnDefinition); + dbTypeMap.Set(DbType.StringFixedLength, StringColumnDefinition); + dbTypeMap.Set(DbType.String, StringColumnDefinition); + dbTypeMap.Set(DbType.Boolean, BoolColumnDefinition); + dbTypeMap.Set(DbType.Boolean, BoolColumnDefinition); + dbTypeMap.Set(DbType.Guid, GuidColumnDefinition); + dbTypeMap.Set(DbType.Guid, GuidColumnDefinition); + dbTypeMap.Set(DbType.DateTime, DateTimeColumnDefinition); + dbTypeMap.Set(DbType.DateTime, DateTimeColumnDefinition); + dbTypeMap.Set(DbType.Time, TimeColumnDefinition); + dbTypeMap.Set(DbType.Time, TimeColumnDefinition); + dbTypeMap.Set(DbType.DateTimeOffset, DateTimeOffsetColumnDefinition); + dbTypeMap.Set(DbType.DateTimeOffset, DateTimeOffsetColumnDefinition); - DbTypeMap.Set(DbType.Byte, IntColumnDefinition); - DbTypeMap.Set(DbType.Byte, IntColumnDefinition); - DbTypeMap.Set(DbType.SByte, IntColumnDefinition); - DbTypeMap.Set(DbType.SByte, IntColumnDefinition); - DbTypeMap.Set(DbType.Int16, IntColumnDefinition); - DbTypeMap.Set(DbType.Int16, IntColumnDefinition); - DbTypeMap.Set(DbType.UInt16, IntColumnDefinition); - DbTypeMap.Set(DbType.UInt16, IntColumnDefinition); - DbTypeMap.Set(DbType.Int32, IntColumnDefinition); - DbTypeMap.Set(DbType.Int32, IntColumnDefinition); - DbTypeMap.Set(DbType.UInt32, IntColumnDefinition); - DbTypeMap.Set(DbType.UInt32, IntColumnDefinition); + dbTypeMap.Set(DbType.Byte, IntColumnDefinition); + dbTypeMap.Set(DbType.Byte, IntColumnDefinition); + dbTypeMap.Set(DbType.SByte, IntColumnDefinition); + dbTypeMap.Set(DbType.SByte, IntColumnDefinition); + dbTypeMap.Set(DbType.Int16, IntColumnDefinition); + dbTypeMap.Set(DbType.Int16, IntColumnDefinition); + dbTypeMap.Set(DbType.UInt16, IntColumnDefinition); + dbTypeMap.Set(DbType.UInt16, IntColumnDefinition); + dbTypeMap.Set(DbType.Int32, IntColumnDefinition); + dbTypeMap.Set(DbType.Int32, IntColumnDefinition); + dbTypeMap.Set(DbType.UInt32, IntColumnDefinition); + dbTypeMap.Set(DbType.UInt32, IntColumnDefinition); - DbTypeMap.Set(DbType.Int64, LongColumnDefinition); - DbTypeMap.Set(DbType.Int64, LongColumnDefinition); - DbTypeMap.Set(DbType.UInt64, LongColumnDefinition); - DbTypeMap.Set(DbType.UInt64, LongColumnDefinition); + dbTypeMap.Set(DbType.Int64, LongColumnDefinition); + dbTypeMap.Set(DbType.Int64, LongColumnDefinition); + dbTypeMap.Set(DbType.UInt64, LongColumnDefinition); + dbTypeMap.Set(DbType.UInt64, LongColumnDefinition); - DbTypeMap.Set(DbType.Single, RealColumnDefinition); - DbTypeMap.Set(DbType.Single, RealColumnDefinition); - DbTypeMap.Set(DbType.Double, RealColumnDefinition); - DbTypeMap.Set(DbType.Double, RealColumnDefinition); + dbTypeMap.Set(DbType.Single, RealColumnDefinition); + dbTypeMap.Set(DbType.Single, RealColumnDefinition); + dbTypeMap.Set(DbType.Double, RealColumnDefinition); + dbTypeMap.Set(DbType.Double, RealColumnDefinition); - DbTypeMap.Set(DbType.Decimal, DecimalColumnDefinition); - DbTypeMap.Set(DbType.Decimal, DecimalColumnDefinition); + dbTypeMap.Set(DbType.Decimal, DecimalColumnDefinition); + dbTypeMap.Set(DbType.Decimal, DecimalColumnDefinition); - DbTypeMap.Set(DbType.Binary, BlobColumnDefinition); + dbTypeMap.Set(DbType.Binary, BlobColumnDefinition); + + return dbTypeMap.Create(); } public abstract string ProviderName { get; } @@ -484,19 +490,19 @@ namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax if (type == typeof(string)) { - var valueOrDefault = column.Size != default(int) ? column.Size : DefaultStringLength; + var valueOrDefault = column.Size != default ? column.Size : DefaultStringLength; return string.Format(StringLengthColumnDefinitionFormat, valueOrDefault); } if (type == typeof(decimal)) { - var precision = column.Size != default(int) ? column.Size : DefaultDecimalPrecision; - var scale = column.Precision != default(int) ? column.Precision : DefaultDecimalScale; + var precision = column.Size != default ? column.Size : DefaultDecimalPrecision; + var scale = column.Precision != default ? column.Precision : DefaultDecimalScale; return string.Format(DecimalColumnDefinitionFormat, precision, scale); } - var definition = DbTypeMap.ColumnTypeMap.First(x => x.Key == type).Value; - var dbTypeDefinition = column.Size != default(int) + var definition = DbTypeMap.ColumnTypeMap[type]; + var dbTypeDefinition = column.Size != default ? $"{definition}({column.Size})" : definition; //NOTE Precision is left out diff --git a/src/Umbraco.Persistence.SqlCe/SqlCeSyntaxProvider.cs b/src/Umbraco.Persistence.SqlCe/SqlCeSyntaxProvider.cs index 274c585fa2..62aa933a04 100644 --- a/src/Umbraco.Persistence.SqlCe/SqlCeSyntaxProvider.cs +++ b/src/Umbraco.Persistence.SqlCe/SqlCeSyntaxProvider.cs @@ -25,10 +25,10 @@ namespace Umbraco.Cms.Persistence.SqlCe { _globalSettings = globalSettings; BlobColumnDefinition = "IMAGE"; - // This is silly to have to do this but the way these inherited classes are structured it's the easiest - // way without an overhaul in type map initialization - DbTypeMap.Set(DbType.Binary, BlobColumnDefinition); - + // NOTE: if this column type is used in sqlce, it will prob result in errors since + // SQLCE cannot support this type correctly without 2x columns and a lot of work arounds. + // We don't use this natively within Umbraco but 3rd parties might with SQL server. + DateTimeOffsetColumnDefinition = "DATETIME"; } public override string ProviderName => Constants.DatabaseProviders.SqlCe;