diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs new file mode 100644 index 00000000..3bbc9237 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -0,0 +1,74 @@ +using System; +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_GetColumnsDefaultTypeTests : PostgreSQLTransformationProviderTestBase +{ + private const decimal DecimalDefaultValue = 14.56565m; + + [Test] + public void GetColumns_DataTypeResolveSucceeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, DecimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); + var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); + var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); + var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); + var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); + var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(DecimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs new file mode 100644 index 00000000..8c169b08 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs @@ -0,0 +1,74 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_GetColumnTypeTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void GetColumns_DataTypeResolveSucceeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string stringColumnName1 = "stringcolumn1"; + const string stringColumnName2 = "stringcolumn2"; + const string binaryColumnName1 = "binarycolumn"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime), + new Column(dateTimeColumnName2, DbType.DateTime2), + new Column(decimalColumnName1, DbType.Decimal), + new Column(guidColumnName1, DbType.Guid), + new Column(booleanColumnName1, DbType.Boolean), + new Column(int32ColumnName1, DbType.Int32), + new Column(int64ColumnName1, DbType.Int64), + new Column(stringColumnName1, DbType.String), + new Column(stringColumnName2, DbType.String) { Size = 30 }, + new Column(binaryColumnName1, DbType.Binary) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); + var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); + var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); + var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); + var int64column1 = columns.Single(x => x.Name == int64ColumnName1); + var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); + var binaryColumn1 = columns.Single(x => x.Name == binaryColumnName1); + + + // Assert + Assert.That(dateTimeColumn1.Type, Is.EqualTo(DbType.DateTime)); + Assert.That(dateTimeColumn1.Precision, Is.EqualTo(3)); + Assert.That(dateTimeColumn2.Type, Is.EqualTo(DbType.DateTime2)); + Assert.That(dateTimeColumn2.Precision, Is.EqualTo(6)); + Assert.That(decimalColumn1.Type, Is.EqualTo(DbType.Decimal)); + Assert.That(decimalColumn1.Precision, Is.EqualTo(19)); + Assert.That(decimalColumn1.Scale, Is.EqualTo(5)); + Assert.That(guidColumn1.Type, Is.EqualTo(DbType.Guid)); + Assert.That(booleanColumn1.Type, Is.EqualTo(DbType.Boolean)); + Assert.That(int32Column1.Type, Is.EqualTo(DbType.Int32)); + Assert.That(int64column1.Type, Is.EqualTo(DbType.Int64)); + Assert.That(stringColumn1.Type, Is.EqualTo(DbType.String)); + Assert.That(stringColumn2.Type, Is.EqualTo(DbType.String)); + Assert.That(stringColumn2.Size, Is.EqualTo(30)); + Assert.That(binaryColumn1.Type, Is.EqualTo(DbType.Binary)); + } +} diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index 6d497bc3..765a98ac 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -11,6 +11,7 @@ #endregion +using System; using System.Data; namespace DotNetProjects.Migrator.Framework; @@ -20,6 +21,8 @@ namespace DotNetProjects.Migrator.Framework; /// public class Column : IColumn, IDbField { + private object _defaultValue; + public Column(string name) { Name = name; @@ -147,13 +150,34 @@ public DbType Type public int Size { get; set; } + /// + /// Gets or sets the precision for NUMERIC/DECIMAL + /// public int? Precision { get; set; } + /// + /// Gets or sets the scale for NUMERIC/DECIMAL + /// public int? Scale { get; set; } public ColumnProperty ColumnProperty { get; set; } - public object DefaultValue { get; set; } + public object DefaultValue + { + get => _defaultValue; + set + { + if (value is DateTime defaultValueDateTime) + { + if (defaultValueDateTime.Kind != DateTimeKind.Utc) + { + throw new Exception("We only accept UTC values as default DateTime values."); + } + } + + _defaultValue = value; + } + } public bool IsIdentity { diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index d66ae1fc..7a8d9e49 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using DotNetProjects.Migrator.Framework; namespace DotNetProjects.Migrator.Providers; @@ -344,7 +345,9 @@ public virtual string Default(object defaultValue) } else if (defaultValue is Guid) { - return string.Format("DEFAULT '{0}'", defaultValue.ToString()); + var guidValue = string.Format("DEFAULT '{0}'", defaultValue.ToString()); + + return guidValue; } else if (defaultValue is DateTime) { @@ -355,6 +358,16 @@ public virtual string Default(object defaultValue) defaultValue = ((string)defaultValue).Replace("'", "''"); defaultValue = "'" + defaultValue + "'"; } + else if (defaultValue is decimal) + { + // .ToString("N") does not exist in old .NET version + defaultValue = Convert.ToString(defaultValue, CultureInfo.InvariantCulture); + } + else if (defaultValue is byte[] byteArray) + { + var convertedString = BitConverter.ToString(byteArray).Replace("-", "").ToLower(); + defaultValue = $"'\\x{convertedString}'"; + } return string.Format("DEFAULT {0}", defaultValue); } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 9923db1f..07d00246 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -18,8 +18,13 @@ public PostgreSQLDialect() RegisterColumnType(DbType.Byte, "int2"); RegisterColumnType(DbType.Currency, "decimal(16,4)"); RegisterColumnType(DbType.Date, "date"); - RegisterColumnType(DbType.DateTime, "timestamptz"); - RegisterColumnType(DbType.DateTime2, "timestamptz"); + + // 8 bytes - resolution 1 microsecond + RegisterColumnType(DbType.DateTime, "timestamp(3)"); + + // 8 bytes - resolution 1 microsecond + // We do not use timezone any more - this is near a datetime2 in SQL Server + RegisterColumnType(DbType.DateTime2, "timestamp(6)"); RegisterColumnType(DbType.DateTimeOffset, "timestamptz"); RegisterColumnType(DbType.Decimal, "decimal(19,5)"); RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index c6f391ab..9cc1a855 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -16,6 +16,9 @@ using System.Collections.Generic; using System.Data; using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; using Index = DotNetProjects.Migrator.Framework.Index; namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; @@ -25,6 +28,8 @@ namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; /// public class PostgreSQLTransformationProvider : TransformationProvider { + private Regex stripSingleQuoteRegEx = new("(?<=')[^']*(?=')"); + public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) : base(dialect, connectionString, defaultSchema, scope) { @@ -246,73 +251,276 @@ public override string[] GetTables() public override Column[] GetColumns(string table) { + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("SELECT"); + stringBuilder.AppendLine(" COLUMN_NAME,"); + stringBuilder.AppendLine(" IS_NULLABLE,"); + stringBuilder.AppendLine(" COLUMN_DEFAULT,"); + stringBuilder.AppendLine(" DATA_TYPE,"); + stringBuilder.AppendLine(" DATETIME_PRECISION,"); + stringBuilder.AppendLine(" CHARACTER_MAXIMUM_LENGTH,"); + stringBuilder.AppendLine(" NUMERIC_PRECISION,"); + stringBuilder.AppendLine(" NUMERIC_SCALE"); + stringBuilder.AppendLine($"FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = lower('{table}');"); + var columns = new List(); + using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - string.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) + using (var reader = ExecuteQuery(cmd, stringBuilder.ToString())) { - // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre while (reader.Read()) { - var column = new Column(reader[0].ToString(), DbType.String); - var isNullable = reader.GetString(1) == "YES"; - var defaultValue = reader.GetValue(2); - - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + var defaultValueOrdinal = reader.GetOrdinal("COLUMN_DEFAULT"); + var characterMaximumLengthOrdinal = reader.GetOrdinal("CHARACTER_MAXIMUM_LENGTH"); + var dateTimePrecisionOrdinal = reader.GetOrdinal("DATETIME_PRECISION"); + var numericPrecisionOrdinal = reader.GetOrdinal("NUMERIC_PRECISION"); + var numericScaleOrdinal = reader.GetOrdinal("NUMERIC_SCALE"); + + var columnName = reader.GetString(reader.GetOrdinal("COLUMN_NAME")); + var isNullable = reader.GetString(reader.GetOrdinal("IS_NULLABLE")) == "YES"; + var defaultValueString = reader.IsDBNull(defaultValueOrdinal) ? null : reader.GetString(defaultValueOrdinal); + var dataTypeString = reader.GetString(reader.GetOrdinal("DATA_TYPE")); + var dateTimePrecision = reader.IsDBNull(dateTimePrecisionOrdinal) ? null : (int?)reader.GetInt32(dateTimePrecisionOrdinal); + var characterMaximumLength = reader.IsDBNull(characterMaximumLengthOrdinal) ? null : (int?)reader.GetInt32(characterMaximumLengthOrdinal); + var numericPrecision = reader.IsDBNull(numericPrecisionOrdinal) ? null : (int?)reader.GetInt32(numericPrecisionOrdinal); + var numericScale = reader.IsDBNull(numericScaleOrdinal) ? null : (int?)reader.GetInt32(numericScaleOrdinal); + + DbType dbType = 0; + int? precision = null; + int? scale = null; + int? size = null; + + if (new[] { "timestamptz", "timestamp with time zone" }.Contains(dataTypeString)) + { + dbType = DbType.DateTimeOffset; + precision = dateTimePrecision; + } + else if (dataTypeString == "timestamp" || dataTypeString == "timestamp without time zone") + { + // 6 is the maximum in PostgreSQL + if (dateTimePrecision > 5) + { + dbType = DbType.DateTime2; + } + else + { + dbType = DbType.DateTime; + } - if (defaultValue != null && defaultValue != DBNull.Value) + precision = dateTimePrecision; + } + else if (dataTypeString == "smallint") + { + dbType = DbType.Int16; + } + else if (dataTypeString == "integer") + { + dbType = DbType.Int32; + } + else if (dataTypeString == "bigint") + { + dbType = DbType.Int64; + } + else if (dataTypeString == "numeric") + { + dbType = DbType.Decimal; + precision = numericPrecision; + scale = numericScale; + } + else if (dataTypeString == "real") + { + dbType = DbType.Single; + } + else if (dataTypeString == "money") + { + dbType = DbType.Currency; + } + else if (dataTypeString == "date") + { + dbType = DbType.Date; + } + else if (dataTypeString == "byte") + { + dbType = DbType.Binary; + } + else if (dataTypeString == "uuid") + { + dbType = DbType.Guid; + } + else if (dataTypeString == "xml") + { + dbType = DbType.Xml; + } + else if (dataTypeString == "time") + { + dbType = DbType.Time; + } + else if (dataTypeString == "interval") + { + throw new NotImplementedException(); + } + else if (dataTypeString == "boolean") + { + dbType = DbType.Boolean; + } + else if (dataTypeString == "text" || dataTypeString == "character varying") + { + dbType = DbType.String; + size = characterMaximumLength; + } + else if (dataTypeString == "bytea") + { + dbType = DbType.Binary; + } + else if (dataTypeString == "character" || dataTypeString.StartsWith("character(")) { - column.DefaultValue = defaultValue; + throw new NotSupportedException("Data type 'character' detected. 'character' is not supported. Use 'text' or 'character varying' instead."); } + else + { + throw new NotImplementedException("The data type is not implemented. Please file an issue."); + } + + var column = new Column(columnName, dbType) + { + Precision = precision, + Scale = scale, + // Size should be nullable + Size = size ?? 0 + }; + + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - if (column.DefaultValue != null) + if (defaultValueString != null) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = long.Parse(column.DefaultValue.ToString()); + column.DefaultValue = long.Parse(defaultValueString.ToString()); } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); + column.DefaultValue = ulong.Parse(defaultValueString.ToString()); } else if (column.Type == DbType.Double || column.Type == DbType.Single) { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + column.DefaultValue = double.Parse(defaultValueString.ToString()); } else if (column.Type == DbType.Boolean) { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + var truthy = new[] { "1", "TRUE", "YES", "'true'", "on", "'on'", "t", "'t'" }; + var falsy = new[] { "0", "FALSE", "NO", "'false'", "off", "'off'", "f", "'f'" }; + + if (truthy.Any(x => x.Equals(defaultValueString.Trim(), StringComparison.OrdinalIgnoreCase))) + { + column.DefaultValue = true; + } + else if (falsy.Any(x => x.Equals(defaultValueString.Trim(), StringComparison.OrdinalIgnoreCase))) + { + column.DefaultValue = false; + } + else + { + throw new NotImplementedException($"Cannot interpret the given default value in column '{column.Name}'"); + } } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - if (column.DefaultValue is string defVal) + if (defaultValueString.StartsWith("'")) { - var dt = defVal; - if (defVal.StartsWith("'")) + var match = stripSingleQuoteRegEx.Match(defaultValueString); + + if (!match.Success) { - dt = defVal.Substring(1, defVal.Length - 2); + throw new Exception("Postgre default value for date time: Single quotes around the date time string are expected."); } - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; + var timeString = match.Value; + + // We convert to UTC since we restrict date time default values to UTC on default value definition. + var dateTimeExtracted = DateTime.ParseExact(timeString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); + + column.DefaultValue = dateTimeExtracted; + } + else + { + throw new NotImplementedException(); } } else if (column.Type == DbType.Guid) { - if (column.DefaultValue is string defVal) + if (defaultValueString.StartsWith("'")) + { + var match = stripSingleQuoteRegEx.Match(defaultValueString); + + if (!match.Success) + { + throw new Exception("Postgre default value for uniqueidentifier: Single quotes around the Guid string are expected."); + } + + column.DefaultValue = Guid.Parse(match.Value); + } + else + { + throw new NotImplementedException(); + } + } + else if (column.Type == DbType.Decimal) + { + column.DefaultValue = decimal.Parse(defaultValueString, CultureInfo.InvariantCulture); + } + else if (column.Type == DbType.String) + { + if (defaultValueString.StartsWith("'")) + { + var match = stripSingleQuoteRegEx.Match(defaultValueString); + + if (!match.Success) + { + throw new Exception("Postgre default value for date time: Single quotes around the date time string are expected."); + } + + column.DefaultValue = match.Value; + } + else + { + throw new NotImplementedException(); + } + } + else if (column.Type == DbType.Binary) + { + if (defaultValueString.StartsWith("'")) { - var dt = defVal; - if (defVal.StartsWith("'")) + var match = stripSingleQuoteRegEx.Match(defaultValueString); + + if (!match.Success) + { + throw new Exception("Postgre default value for bytea: Single quotes around the bytea string are expected."); + } + + var singleQuoteString = match.Value; + + if (!singleQuoteString.StartsWith("\\x")) { - dt = defVal.Substring(1, defVal.Length - 2); + throw new Exception(@"Postgre \x notation expected."); } - var d = Guid.Parse(dt); - column.DefaultValue = d; + var hexString = singleQuoteString.Substring(2); + + // Not available in old .NET version: Convert.FromHexString(hexString); + + column.DefaultValue = Enumerable.Range(0, hexString.Length / 2) + .Select(x => Convert.ToByte(hexString.Substring(x * 2, 2), 16)) + .ToArray(); + } + else + { + throw new NotImplementedException(); } } + else + { + throw new NotImplementedException(); + } } columns.Add(column); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 023e76c5..f7f6b9e6 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1784,6 +1784,14 @@ public virtual List GetPrimaryKeys(IEnumerable columns) public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) { + if (defaultValue is DateTime defaultValueDateTime) + { + if (defaultValueDateTime.Kind != DateTimeKind.Utc) + { + throw new Exception("Only UTC values are accepted as default DateTime values."); + } + } + table = QuoteTableNameIfRequired(table); column = this.QuoteColumnNameIfRequired(column); var def = Dialect.Default(defaultValue);