diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs b/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs
index 19ec0738c8..ae16a9735f 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Constants.cs
@@ -1,12 +1,12 @@
namespace Umbraco.Cms.Persistence.SqlServer;
///
-/// Constants related to SQLite.
+/// Constants related to SQLite.
///
public static class Constants
{
///
- /// SQLite provider name.
+ /// SQLite provider name.
///
public const string ProviderName = "Microsoft.Data.SqlClient";
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ColumnInSchemaDto.cs b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ColumnInSchemaDto.cs
index 65bd0b5d65..0c09f87d51 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ColumnInSchemaDto.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ColumnInSchemaDto.cs
@@ -1,25 +1,24 @@
using NPoco;
-namespace Umbraco.Cms.Persistence.SqlServer.Dtos
+namespace Umbraco.Cms.Persistence.SqlServer.Dtos;
+
+internal class ColumnInSchemaDto
{
- internal class ColumnInSchemaDto
- {
- [Column("TABLE_NAME")]
- public string TableName { get; set; } = null!;
+ [Column("TABLE_NAME")]
+ public string TableName { get; set; } = null!;
- [Column("COLUMN_NAME")]
- public string ColumnName { get; set; } = null!;
+ [Column("COLUMN_NAME")]
+ public string ColumnName { get; set; } = null!;
- [Column("ORDINAL_POSITION")]
- public int OrdinalPosition { get; set; }
+ [Column("ORDINAL_POSITION")]
+ public int OrdinalPosition { get; set; }
- [Column("COLUMN_DEFAULT")]
- public string ColumnDefault { get; set; } = null!;
+ [Column("COLUMN_DEFAULT")]
+ public string ColumnDefault { get; set; } = null!;
- [Column("IS_NULLABLE")]
- public string IsNullable { get; set; } = null!;
+ [Column("IS_NULLABLE")]
+ public string IsNullable { get; set; } = null!;
- [Column("DATA_TYPE")]
- public string DataType { get; set; } = null!;
- }
+ [Column("DATA_TYPE")]
+ public string DataType { get; set; } = null!;
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ConstraintPerColumnDto.cs b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ConstraintPerColumnDto.cs
index 351979570c..b0299a489d 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ConstraintPerColumnDto.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ConstraintPerColumnDto.cs
@@ -1,16 +1,15 @@
using NPoco;
-namespace Umbraco.Cms.Persistence.SqlServer.Dtos
+namespace Umbraco.Cms.Persistence.SqlServer.Dtos;
+
+internal class ConstraintPerColumnDto
{
- internal class ConstraintPerColumnDto
- {
- [Column("TABLE_NAME")]
- public string TableName { get; set; } = null!;
+ [Column("TABLE_NAME")]
+ public string TableName { get; set; } = null!;
- [Column("COLUMN_NAME")]
- public string ColumnName { get; set; } = null!;
+ [Column("COLUMN_NAME")]
+ public string ColumnName { get; set; } = null!;
- [Column("CONSTRAINT_NAME")]
- public string ConstraintName { get; set; } = null!;
- }
+ [Column("CONSTRAINT_NAME")]
+ public string ConstraintName { get; set; } = null!;
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ConstraintPerTableDto.cs b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ConstraintPerTableDto.cs
index 3a633d4e0e..fe87ef2909 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ConstraintPerTableDto.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/ConstraintPerTableDto.cs
@@ -1,13 +1,12 @@
using NPoco;
-namespace Umbraco.Cms.Persistence.SqlServer.Dtos
-{
- internal class ConstraintPerTableDto
- {
- [Column("TABLE_NAME")]
- public string TableName { get; set; } = null!;
+namespace Umbraco.Cms.Persistence.SqlServer.Dtos;
- [Column("CONSTRAINT_NAME")]
- public string ConstraintName { get; set; } = null!;
- }
+internal class ConstraintPerTableDto
+{
+ [Column("TABLE_NAME")]
+ public string TableName { get; set; } = null!;
+
+ [Column("CONSTRAINT_NAME")]
+ public string ConstraintName { get; set; } = null!;
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/DefaultConstraintPerColumnDto.cs b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/DefaultConstraintPerColumnDto.cs
index e0e1dfbe2f..a1bde415a3 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/DefaultConstraintPerColumnDto.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/DefaultConstraintPerColumnDto.cs
@@ -1,18 +1,18 @@
using NPoco;
-namespace Umbraco.Cms.Persistence.SqlServer.Dtos
+namespace Umbraco.Cms.Persistence.SqlServer.Dtos;
+
+internal class DefaultConstraintPerColumnDto
{
- internal class DefaultConstraintPerColumnDto
- {
- [Column("TABLE_NAME")] public string TableName { get; set; } = null!;
+ [Column("TABLE_NAME")]
+ public string TableName { get; set; } = null!;
- [Column("COLUMN_NAME")]
- public string ColumnName { get; set; } = null!;
+ [Column("COLUMN_NAME")]
+ public string ColumnName { get; set; } = null!;
- [Column("NAME")]
- public string Name { get; set; } = null!;
+ [Column("NAME")]
+ public string Name { get; set; } = null!;
- [Column("DEFINITION")]
- public string Definition { get; set; } = null!;
- }
+ [Column("DEFINITION")]
+ public string Definition { get; set; } = null!;
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/DefinedIndexDto.cs b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/DefinedIndexDto.cs
index e78f354e46..e85d91f1dd 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Dtos/DefinedIndexDto.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Dtos/DefinedIndexDto.cs
@@ -1,20 +1,18 @@
using NPoco;
-namespace Umbraco.Cms.Persistence.SqlServer.Dtos
+namespace Umbraco.Cms.Persistence.SqlServer.Dtos;
+
+internal class DefinedIndexDto
{
- internal class DefinedIndexDto
- {
+ [Column("TABLE_NAME")]
+ public string TableName { get; set; } = null!;
- [Column("TABLE_NAME")]
- public string TableName { get; set; } = null!;
+ [Column("INDEX_NAME")]
+ public string IndexName { get; set; } = null!;
- [Column("INDEX_NAME")]
- public string IndexName { get; set; } = null!;
+ [Column("COLUMN_NAME")]
+ public string ColumnName { get; set; } = null!;
- [Column("COLUMN_NAME")]
- public string ColumnName { get; set; } = null!;
-
- [Column("UNIQUE")]
- public short Unique { get; set; }
- }
+ [Column("UNIQUE")]
+ public short Unique { get; set; }
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Interceptors/SqlServerAddMiniProfilerInterceptor.cs b/src/Umbraco.Cms.Persistence.SqlServer/Interceptors/SqlServerAddMiniProfilerInterceptor.cs
index 7c5df6c497..43541ec2a3 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Interceptors/SqlServerAddMiniProfilerInterceptor.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Interceptors/SqlServerAddMiniProfilerInterceptor.cs
@@ -1,11 +1,12 @@
using System.Data.Common;
using NPoco;
using StackExchange.Profiling;
+using StackExchange.Profiling.Data;
namespace Umbraco.Cms.Persistence.SqlServer.Interceptors;
public class SqlServerAddMiniProfilerInterceptor : SqlServerConnectionInterceptor
{
public override DbConnection OnConnectionOpened(IDatabase database, DbConnection conn)
- => new StackExchange.Profiling.Data.ProfiledDbConnection(conn, MiniProfiler.Current);
+ => new ProfiledDbConnection(conn, MiniProfiler.Current);
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Interceptors/SqlServerAddRetryPolicyInterceptor.cs b/src/Umbraco.Cms.Persistence.SqlServer/Interceptors/SqlServerAddRetryPolicyInterceptor.cs
index bdf5745d42..139efea85f 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Interceptors/SqlServerAddRetryPolicyInterceptor.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Interceptors/SqlServerAddRetryPolicyInterceptor.cs
@@ -21,8 +21,12 @@ public class SqlServerAddRetryPolicyInterceptor : SqlServerConnectionInterceptor
return conn;
}
- RetryPolicy? connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(_connectionStrings.CurrentValue.ConnectionString);
- RetryPolicy? commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(_connectionStrings.CurrentValue.ConnectionString);
+ RetryPolicy? connectionRetryPolicy =
+ RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(_connectionStrings.CurrentValue
+ .ConnectionString);
+ RetryPolicy? commandRetryPolicy =
+ RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(_connectionStrings.CurrentValue
+ .ConnectionString);
if (connectionRetryPolicy == null && commandRetryPolicy == null)
{
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/BulkDataReader.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/BulkDataReader.cs
index e9784ce270..d74511bf11 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/BulkDataReader.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/BulkDataReader.cs
@@ -3,1503 +3,1490 @@ using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Globalization;
+using System.Text;
using Microsoft.Data.SqlClient;
-namespace Umbraco.Cms.Persistence.SqlServer.Services
+namespace Umbraco.Cms.Persistence.SqlServer.Services;
+
+///
+/// A base implementation of that is suitable for
+/// .
+///
+///
+/// Borrowed from Microsoft:
+/// See: https://blogs.msdn.microsoft.com/anthonybloesch/2013/01/23/bulk-loading-data-with-idatareader-and-sqlbulkcopy/
+/// This implementation is designed to be very memory efficient requiring few memory resources and to support
+/// rapid transfer of data to SQL Server.
+/// Subclasses should implement , ,
+/// , ,
+/// .
+/// If they contain disposable resources they should override .
+/// SD: Alternatively, we could have used a LinqEntityDataReader which is nicer to use but it uses quite a lot of
+/// reflection and
+/// I thought this would just be quicker.
+/// Simple example of that:
+/// https://github.com/gridsum/DataflowEx/blob/master/Gridsum.DataflowEx/Databases/BulkDataReader.cs
+/// Full example of that:
+/// https://github.com/matthewschrager/Repository/blob/master/Repository.EntityFramework/EntityDataReader.cs
+/// So we know where to find that if we ever need it, these would convert any Linq data source to an IDataReader
+///
+internal abstract class BulkDataReader : IDataReader
{
+ #region Fields
+
///
- /// A base implementation of that is suitable for .
+ /// The containing the input row set's schema information
+ ///
+ /// requires to function correctly.
+ ///
+ private DataTable? _schemaTable = new();
+
+ ///
+ /// The mapping from the row set input to the target table's columns.
+ ///
+ private List? _columnMappings = new();
+
+ #endregion
+
+ #region Subclass utility routines
+
+ ///
+ /// The mapping from the row set input to the target table's columns.
///
///
- ///
- /// Borrowed from Microsoft:
- /// See: https://blogs.msdn.microsoft.com/anthonybloesch/2013/01/23/bulk-loading-data-with-idatareader-and-sqlbulkcopy/
- ///
- /// This implementation is designed to be very memory efficient requiring few memory resources and to support
- /// rapid transfer of data to SQL Server.
- ///
- /// Subclasses should implement , ,
- /// , , .
- /// If they contain disposable resources they should override .
- ///
- /// SD: Alternatively, we could have used a LinqEntityDataReader which is nicer to use but it uses quite a lot of reflection and
- /// I thought this would just be quicker.
- /// Simple example of that: https://github.com/gridsum/DataflowEx/blob/master/Gridsum.DataflowEx/Databases/BulkDataReader.cs
- /// Full example of that: https://github.com/matthewschrager/Repository/blob/master/Repository.EntityFramework/EntityDataReader.cs
- /// So we know where to find that if we ever need it, these would convert any Linq data source to an IDataReader
- ///
+ /// If necessary, will be called to initialize the mapping.
///
- internal abstract class BulkDataReader : IDataReader
+ public ReadOnlyCollection ColumnMappings
{
-
- #region Fields
-
- ///
- /// The containing the input row set's schema information
- /// requires to function correctly.
- ///
- private DataTable? _schemaTable = new DataTable();
-
- ///
- /// The mapping from the row set input to the target table's columns.
- ///
- private List? _columnMappings = new List();
-
- #endregion
-
- #region Subclass utility routines
-
- ///
- /// The mapping from the row set input to the target table's columns.
- ///
- ///
- /// If necessary, will be called to initialize the mapping.
- ///
- public ReadOnlyCollection ColumnMappings
+ get
{
- get
+ if (_columnMappings?.Count == 0)
{
- if (this._columnMappings?.Count == 0)
+ // Need to add the column definitions and mappings.
+ AddSchemaTableRows();
+
+ if (_columnMappings.Count == 0)
{
- // Need to add the column definitions and mappings.
- AddSchemaTableRows();
-
- if (this._columnMappings.Count == 0)
- {
- throw new InvalidOperationException("AddSchemaTableRows did not add rows.");
- }
-
- Debug.Assert(this._schemaTable?.Rows.Count == FieldCount);
+ throw new InvalidOperationException("AddSchemaTableRows did not add rows.");
}
- return new ReadOnlyCollection(_columnMappings!);
+ Debug.Assert(_schemaTable?.Rows.Count == FieldCount);
+ }
+
+ return new ReadOnlyCollection(_columnMappings!);
+ }
+ }
+
+ ///
+ /// The name of the input row set's schema.
+ ///
+ ///
+ /// This may be different from the target schema but usually they are identical.
+ ///
+ protected abstract string SchemaName
+ {
+ get;
+ }
+
+ ///
+ /// The name of the input row set's table.
+ ///
+ ///
+ /// This may be different from the target table but usually they are identical.
+ ///
+ protected abstract string TableName
+ {
+ get;
+ }
+
+ ///
+ /// Adds the input row set's schema to the object.
+ ///
+ ///
+ /// Call
+ ///
+ /// to do this for each row.
+ ///
+ ///
+ protected abstract void AddSchemaTableRows();
+
+ ///
+ /// For each , the optional columns that may have values.
+ ///
+ ///
+ /// This is used for checking the parameters of
+ ///
+ /// .
+ ///
+ ///
+ private static readonly Dictionary> AllowedOptionalColumnCombinations = new()
+ {
+ {SqlDbType.BigInt, new List()},
+ {SqlDbType.Binary, new List {SchemaTableColumn.ColumnSize}},
+ {SqlDbType.Bit, new List()},
+ {SqlDbType.Char, new List {SchemaTableColumn.ColumnSize}},
+ {SqlDbType.Date, new List()},
+ {SqlDbType.DateTime, new List()},
+ {SqlDbType.DateTime2, new List {SchemaTableColumn.NumericPrecision}},
+ {SqlDbType.DateTimeOffset, new List {SchemaTableColumn.NumericPrecision}},
+ {SqlDbType.Decimal, new List {SchemaTableColumn.NumericPrecision, SchemaTableColumn.NumericScale}},
+ {SqlDbType.Float, new List {SchemaTableColumn.NumericPrecision, SchemaTableColumn.NumericScale}},
+ {SqlDbType.Image, new List()},
+ {SqlDbType.Int, new List()},
+ {SqlDbType.Money, new List()},
+ {SqlDbType.NChar, new List {SchemaTableColumn.ColumnSize}},
+ {SqlDbType.NText, new List()},
+ {SqlDbType.NVarChar, new List {SchemaTableColumn.ColumnSize}},
+ {SqlDbType.Real, new List()},
+ {SqlDbType.SmallDateTime, new List()},
+ {SqlDbType.SmallInt, new List()},
+ {SqlDbType.SmallMoney, new List()},
+ {SqlDbType.Structured, new List()},
+ {SqlDbType.Text, new List()},
+ {SqlDbType.Time, new List {SchemaTableColumn.NumericPrecision}},
+ {SqlDbType.Timestamp, new List()},
+ {SqlDbType.TinyInt, new List()},
+ {SqlDbType.Udt, new List {DataTypeNameSchemaColumn}},
+ {SqlDbType.UniqueIdentifier, new List()},
+ {SqlDbType.VarBinary, new List {SchemaTableColumn.ColumnSize}},
+ {SqlDbType.VarChar, new List {SchemaTableColumn.ColumnSize}},
+ {SqlDbType.Variant, new List()},
+ {
+ SqlDbType.Xml,
+ new List
+ {
+ XmlSchemaCollectionDatabaseSchemaColumn,
+ XmlSchemaCollectionOwningSchemaSchemaColumn,
+ XmlSchemaCollectionNameSchemaColumn
}
}
+ };
- ///
- /// The name of the input row set's schema.
- ///
- ///
- /// This may be different from the target schema but usually they are identical.
- ///
- protected abstract string SchemaName
+ ///
+ /// A helper method to support .
+ ///
+ ///
+ /// This methods does extensive argument checks. These errors will cause hard to diagnose exceptions in latter
+ /// processing so it is important to detect them when they can be easily associated with the code defect.
+ ///
+ ///
+ /// The combination of values for the parameters is not supported.
+ ///
+ ///
+ /// A null value for the parameter is not supported.
+ ///
+ ///
+ /// The name of the column.
+ ///
+ ///
+ /// The size of the column which may be null if not applicable.
+ ///
+ ///
+ /// The precision of the column which may be null if not applicable.
+ ///
+ ///
+ /// The scale of the column which may be null if not applicable.
+ ///
+ ///
+ /// Are the column values unique (i.e. never duplicated)?
+ ///
+ ///
+ /// Is the column part of the primary key?
+ ///
+ ///
+ /// Is the column nullable (i.e. optional)?
+ ///
+ ///
+ /// The corresponding .
+ ///
+ ///
+ /// The schema name of the UDT.
+ ///
+ ///
+ /// The type name of the UDT.
+ ///
+ ///
+ /// For XML columns the schema collection's database name. Otherwise, null.
+ ///
+ ///
+ /// For XML columns the schema collection's schema name. Otherwise, null.
+ ///
+ ///
+ /// For XML columns the schema collection's name. Otherwise, null.
+ ///
+ ///
+ protected void AddSchemaTableRow(
+ string columnName,
+ int? columnSize,
+ short? numericPrecision,
+ short? numericScale,
+ bool isUnique,
+ bool isKey,
+ bool allowDbNull,
+ SqlDbType providerType,
+ string? udtSchema,
+ string? udtType,
+ string? xmlSchemaCollectionDatabase,
+ string? xmlSchemaCollectionOwningSchema,
+ string? xmlSchemaCollectionName)
+ {
+ if (string.IsNullOrEmpty(columnName))
{
- get;
+ throw new ArgumentException("columnName must be a nonempty string.");
}
- ///
- /// The name of the input row set's table.
- ///
- ///
- /// This may be different from the target table but usually they are identical.
- ///
- protected abstract string TableName
+ if (columnSize.HasValue && columnSize.Value <= 0)
{
- get;
+ throw new ArgumentOutOfRangeException("columnSize");
}
- ///
- /// Adds the input row set's schema to the object.
- ///
- ///
- /// Call
- /// to do this for each row.
- ///
- ///
- protected abstract void AddSchemaTableRows();
-
- ///
- /// For each , the optional columns that may have values.
- ///
- ///
- /// This is used for checking the parameters of .
- ///
- ///
- private static readonly Dictionary> AllowedOptionalColumnCombinations = new Dictionary>
+ if (numericPrecision.HasValue && numericPrecision.Value <= 0)
{
- { SqlDbType.BigInt, new List { } },
- { SqlDbType.Binary, new List { SchemaTableColumn.ColumnSize } },
- { SqlDbType.Bit, new List { } },
- { SqlDbType.Char, new List { SchemaTableColumn.ColumnSize } },
- { SqlDbType.Date, new List { } },
- { SqlDbType.DateTime, new List { } },
- { SqlDbType.DateTime2, new List { SchemaTableColumn.NumericPrecision } },
- { SqlDbType.DateTimeOffset, new List { SchemaTableColumn.NumericPrecision } },
- { SqlDbType.Decimal, new List { SchemaTableColumn.NumericPrecision, SchemaTableColumn.NumericScale } },
- { SqlDbType.Float, new List { SchemaTableColumn.NumericPrecision, SchemaTableColumn.NumericScale } },
- { SqlDbType.Image, new List { } },
- { SqlDbType.Int, new List { } },
- { SqlDbType.Money, new List { } },
- { SqlDbType.NChar, new List { SchemaTableColumn.ColumnSize } },
- { SqlDbType.NText, new List { } },
- { SqlDbType.NVarChar, new List { SchemaTableColumn.ColumnSize } },
- { SqlDbType.Real, new List { } },
- { SqlDbType.SmallDateTime, new List { } },
- { SqlDbType.SmallInt, new List { } },
- { SqlDbType.SmallMoney, new List { } },
- { SqlDbType.Structured, new List { } },
- { SqlDbType.Text, new List { } },
- { SqlDbType.Time, new List { SchemaTableColumn.NumericPrecision } },
- { SqlDbType.Timestamp, new List { } },
- { SqlDbType.TinyInt, new List { } },
- { SqlDbType.Udt, new List { BulkDataReader.DataTypeNameSchemaColumn } },
- { SqlDbType.UniqueIdentifier, new List { } },
- { SqlDbType.VarBinary, new List { SchemaTableColumn.ColumnSize } },
- { SqlDbType.VarChar, new List { SchemaTableColumn.ColumnSize } },
- { SqlDbType.Variant, new List { } },
- { SqlDbType.Xml, new List { BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, BulkDataReader.XmlSchemaCollectionNameSchemaColumn } }
- };
+ throw new ArgumentOutOfRangeException("numericPrecision");
+ }
- ///
- /// A helper method to support .
- ///
- ///
- /// This methods does extensive argument checks. These errors will cause hard to diagnose exceptions in latter
- /// processing so it is important to detect them when they can be easily associated with the code defect.
- ///
- ///
- /// The combination of values for the parameters is not supported.
- ///
- ///
- /// A null value for the parameter is not supported.
- ///
- ///
- /// The name of the column.
- ///
- ///
- /// The size of the column which may be null if not applicable.
- ///
- ///
- /// The precision of the column which may be null if not applicable.
- ///
- ///
- /// The scale of the column which may be null if not applicable.
- ///
- ///
- /// Are the column values unique (i.e. never duplicated)?
- ///
- ///
- /// Is the column part of the primary key?
- ///
- ///
- /// Is the column nullable (i.e. optional)?
- ///
- ///
- /// The corresponding .
- ///
- ///
- /// The schema name of the UDT.
- ///
- ///
- /// The type name of the UDT.
- ///
- ///
- /// For XML columns the schema collection's database name. Otherwise, null.
- ///
- ///
- /// For XML columns the schema collection's schema name. Otherwise, null.
- ///
- ///
- /// For XML columns the schema collection's name. Otherwise, null.
- ///
- ///
- protected void AddSchemaTableRow(string columnName,
- int? columnSize,
- short? numericPrecision,
- short? numericScale,
- bool isUnique,
- bool isKey,
- bool allowDbNull,
- SqlDbType providerType,
- string? udtSchema,
- string? udtType,
- string? xmlSchemaCollectionDatabase,
- string? xmlSchemaCollectionOwningSchema,
- string? xmlSchemaCollectionName)
+ if (numericScale.HasValue && numericScale.Value < 0)
{
- if (string.IsNullOrEmpty(columnName))
- {
- throw new ArgumentException("columnName must be a nonempty string.");
- }
- else if (columnSize.HasValue && columnSize.Value <= 0)
- {
- throw new ArgumentOutOfRangeException("columnSize");
- }
- else if (numericPrecision.HasValue && numericPrecision.Value <= 0)
- {
- throw new ArgumentOutOfRangeException("numericPrecision");
- }
- else if (numericScale.HasValue && numericScale.Value < 0)
- {
- throw new ArgumentOutOfRangeException("columnSize");
- }
+ throw new ArgumentOutOfRangeException("columnSize");
+ }
- List? allowedOptionalColumnList;
- if (BulkDataReader.AllowedOptionalColumnCombinations.TryGetValue(providerType, out allowedOptionalColumnList))
+ if (AllowedOptionalColumnCombinations.TryGetValue(providerType, out List? allowedOptionalColumnList))
+ {
+ if ((columnSize.HasValue && !allowedOptionalColumnList.Contains(SchemaTableColumn.ColumnSize)) ||
+ (numericPrecision.HasValue &&
+ !allowedOptionalColumnList.Contains(SchemaTableColumn.NumericPrecision)) ||
+ (numericScale.HasValue && !allowedOptionalColumnList.Contains(SchemaTableColumn.NumericScale)) ||
+ (udtSchema != null && !allowedOptionalColumnList.Contains(DataTypeNameSchemaColumn)) ||
+ (udtType != null && !allowedOptionalColumnList.Contains(DataTypeNameSchemaColumn)) ||
+ (xmlSchemaCollectionDatabase != null &&
+ !allowedOptionalColumnList.Contains(XmlSchemaCollectionDatabaseSchemaColumn)) ||
+ (xmlSchemaCollectionOwningSchema != null &&
+ !allowedOptionalColumnList.Contains(XmlSchemaCollectionOwningSchemaSchemaColumn)) ||
+ (xmlSchemaCollectionName != null &&
+ !allowedOptionalColumnList.Contains(XmlSchemaCollectionNameSchemaColumn)))
{
- if ((columnSize.HasValue && !allowedOptionalColumnList.Contains(SchemaTableColumn.ColumnSize)) ||
- (numericPrecision.HasValue && !allowedOptionalColumnList.Contains(SchemaTableColumn.NumericPrecision)) ||
- (numericScale.HasValue && !allowedOptionalColumnList.Contains(SchemaTableColumn.NumericScale)) ||
- (udtSchema != null && !allowedOptionalColumnList.Contains(BulkDataReader.DataTypeNameSchemaColumn)) ||
- (udtType != null && !allowedOptionalColumnList.Contains(BulkDataReader.DataTypeNameSchemaColumn)) ||
- (xmlSchemaCollectionDatabase != null && !allowedOptionalColumnList.Contains(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn)) ||
- (xmlSchemaCollectionOwningSchema != null && !allowedOptionalColumnList.Contains(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn)) ||
- (xmlSchemaCollectionName != null && !allowedOptionalColumnList.Contains(BulkDataReader.XmlSchemaCollectionNameSchemaColumn)))
+ throw new ArgumentException("Columns are set that are incompatible with the value of providerType.");
+ }
+ }
+ else
+ {
+ throw new ArgumentException("providerType is unsupported.");
+ }
+
+ Type dataType; // Corresponding CLR type.
+ string dataTypeName; // Corresponding SQL Server type.
+ var isLong = false; // Is the column a large value column (e.g. nvarchar(max))?
+
+ switch (providerType)
+ {
+ case SqlDbType.BigInt:
+ dataType = typeof(long);
+ dataTypeName = "bigint";
+ break;
+
+ case SqlDbType.Binary:
+ dataType = typeof(byte[]);
+
+ if (!columnSize.HasValue)
{
- throw new ArgumentException("Columns are set that are incompatible with the value of providerType.");
+ throw new ArgumentException("columnSize must be specified for \"binary\" type columns.");
}
- }
- else
- {
- throw new ArgumentException("providerType is unsupported.");
- }
- Type dataType; // Corresponding CLR type.
- string dataTypeName; // Corresponding SQL Server type.
- bool isLong = false; // Is the column a large value column (e.g. nvarchar(max))?
+ if (columnSize > 8000)
+ {
+ throw new ArgumentOutOfRangeException("columnSize");
+ }
- switch (providerType)
- {
- case SqlDbType.BigInt:
- dataType = typeof(long);
- dataTypeName = "bigint";
- break;
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "binary({0})",
+ columnSize.Value);
+ break;
- case SqlDbType.Binary:
- dataType = typeof(byte[]);
+ case SqlDbType.Bit:
+ dataType = typeof(bool);
+ dataTypeName = "bit";
+ break;
- if (!columnSize.HasValue)
- {
- throw new ArgumentException("columnSize must be specified for \"binary\" type columns.");
- }
- else if (columnSize > 8000)
- {
- throw new ArgumentOutOfRangeException("columnSize");
- }
+ case SqlDbType.Char:
+ dataType = typeof(string);
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "binary({0})",
- columnSize.Value);
- break;
+ if (!columnSize.HasValue)
+ {
+ throw new ArgumentException("columnSize must be specified for \"char\" type columns.");
+ }
- case SqlDbType.Bit:
- dataType = typeof(bool);
- dataTypeName = "bit";
- break;
+ if (columnSize > 8000)
+ {
+ throw new ArgumentOutOfRangeException("columnSize");
+ }
- case SqlDbType.Char:
- dataType = typeof(string);
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "char({0})",
+ columnSize.Value);
+ break;
- if (!columnSize.HasValue)
- {
- throw new ArgumentException("columnSize must be specified for \"char\" type columns.");
- }
- else if (columnSize > 8000)
- {
- throw new ArgumentOutOfRangeException("columnSize");
- }
+ case SqlDbType.Date:
+ dataType = typeof(DateTime);
+ dataTypeName = "date";
+ break;
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "char({0})",
- columnSize.Value);
- break;
+ case SqlDbType.DateTime:
+ dataType = typeof(DateTime);
+ dataTypeName = "datetime";
+ break;
- case SqlDbType.Date:
- dataType = typeof(DateTime);
- dataTypeName = "date";
- break;
+ case SqlDbType.DateTime2:
+ dataType = typeof(DateTime);
- case SqlDbType.DateTime:
- dataType = typeof(DateTime);
- dataTypeName = "datetime";
- break;
-
- case SqlDbType.DateTime2:
- dataType = typeof(DateTime);
-
- if (numericPrecision.HasValue)
- {
- if (numericPrecision.Value > 7)
- {
- throw new ArgumentOutOfRangeException("numericPrecision");
- }
-
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "datetime2({0})",
- numericPrecision.Value);
- }
- else
- {
- dataTypeName = "datetime2";
- }
- break;
-
- case SqlDbType.DateTimeOffset:
- dataType = typeof(DateTimeOffset);
-
- if (numericPrecision.HasValue)
- {
- if (numericPrecision.Value > 7)
- {
- throw new ArgumentOutOfRangeException("numericPrecision");
- }
-
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "datetimeoffset({0})",
- numericPrecision.Value);
- }
- else
- {
- dataTypeName = "datetimeoffset";
- }
- break;
-
- case SqlDbType.Decimal:
- dataType = typeof(decimal);
-
- if (!numericPrecision.HasValue || !numericScale.HasValue)
- {
- throw new ArgumentException("numericPrecision and numericScale must be specified for \"decimal\" type columns.");
- }
- else if (numericPrecision > 38)
- {
- throw new ArgumentOutOfRangeException("numericPrecision");
- }
- else if (numericScale.Value > numericPrecision.Value)
- {
- throw new ArgumentException("numericScale must not be larger than numericPrecision for \"decimal\" type columns.");
- }
-
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "decimal({0}, {1})",
- numericPrecision.Value,
- numericScale.Value);
- break;
-
- case SqlDbType.Float:
- dataType = typeof(double);
-
- if (!numericPrecision.HasValue)
- {
- throw new ArgumentException("numericPrecision must be specified for \"float\" type columns");
- }
- else if (numericPrecision > 53)
+ if (numericPrecision.HasValue)
+ {
+ if (numericPrecision.Value > 7)
{
throw new ArgumentOutOfRangeException("numericPrecision");
}
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "float({0})",
- numericPrecision.Value);
- break;
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "datetime2({0})",
+ numericPrecision.Value);
+ }
+ else
+ {
+ dataTypeName = "datetime2";
+ }
- case SqlDbType.Image:
- dataType = typeof(byte[]);
- dataTypeName = "image";
- break;
+ break;
- case SqlDbType.Int:
- dataType = typeof(int);
- dataTypeName = "int";
- break;
+ case SqlDbType.DateTimeOffset:
+ dataType = typeof(DateTimeOffset);
- case SqlDbType.Money:
- dataType = typeof(decimal);
- dataTypeName = "money";
- break;
-
- case SqlDbType.NChar:
- dataType = typeof(string);
-
- if (!columnSize.HasValue)
+ if (numericPrecision.HasValue)
+ {
+ if (numericPrecision.Value > 7)
{
- throw new ArgumentException("columnSize must be specified for \"nchar\" type columns");
+ throw new ArgumentOutOfRangeException("numericPrecision");
}
- else if (columnSize > 4000)
+
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "datetimeoffset({0})",
+ numericPrecision.Value);
+ }
+ else
+ {
+ dataTypeName = "datetimeoffset";
+ }
+
+ break;
+
+ case SqlDbType.Decimal:
+ dataType = typeof(decimal);
+
+ if (!numericPrecision.HasValue || !numericScale.HasValue)
+ {
+ throw new ArgumentException(
+ "numericPrecision and numericScale must be specified for \"decimal\" type columns.");
+ }
+
+ if (numericPrecision > 38)
+ {
+ throw new ArgumentOutOfRangeException("numericPrecision");
+ }
+
+ if (numericScale.Value > numericPrecision.Value)
+ {
+ throw new ArgumentException(
+ "numericScale must not be larger than numericPrecision for \"decimal\" type columns.");
+ }
+
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "decimal({0}, {1})",
+ numericPrecision.Value,
+ numericScale.Value);
+ break;
+
+ case SqlDbType.Float:
+ dataType = typeof(double);
+
+ if (!numericPrecision.HasValue)
+ {
+ throw new ArgumentException("numericPrecision must be specified for \"float\" type columns");
+ }
+
+ if (numericPrecision > 53)
+ {
+ throw new ArgumentOutOfRangeException("numericPrecision");
+ }
+
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "float({0})",
+ numericPrecision.Value);
+ break;
+
+ case SqlDbType.Image:
+ dataType = typeof(byte[]);
+ dataTypeName = "image";
+ break;
+
+ case SqlDbType.Int:
+ dataType = typeof(int);
+ dataTypeName = "int";
+ break;
+
+ case SqlDbType.Money:
+ dataType = typeof(decimal);
+ dataTypeName = "money";
+ break;
+
+ case SqlDbType.NChar:
+ dataType = typeof(string);
+
+ if (!columnSize.HasValue)
+ {
+ throw new ArgumentException("columnSize must be specified for \"nchar\" type columns");
+ }
+
+ if (columnSize > 4000)
+ {
+ throw new ArgumentOutOfRangeException("columnSize");
+ }
+
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "nchar({0})",
+ columnSize.Value);
+ break;
+
+ case SqlDbType.NText:
+ dataType = typeof(string);
+ dataTypeName = "ntext";
+ break;
+
+ case SqlDbType.NVarChar:
+ dataType = typeof(string);
+
+ if (columnSize.HasValue)
+ {
+ if (columnSize > 4000)
{
throw new ArgumentOutOfRangeException("columnSize");
}
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "nchar({0})",
- columnSize.Value);
- break;
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "nvarchar({0})",
+ columnSize.Value);
+ }
+ else
+ {
+ isLong = true;
- case SqlDbType.NText:
- dataType = typeof(string);
- dataTypeName = "ntext";
- break;
+ dataTypeName = "nvarchar(max)";
+ }
- case SqlDbType.NVarChar:
- dataType = typeof(string);
+ break;
- if (columnSize.HasValue)
+ case SqlDbType.Real:
+ dataType = typeof(float);
+ dataTypeName = "real";
+ break;
+
+ case SqlDbType.SmallDateTime:
+ dataType = typeof(DateTime);
+ dataTypeName = "smalldatetime";
+ break;
+
+ case SqlDbType.SmallInt:
+ dataType = typeof(short);
+ dataTypeName = "smallint";
+ break;
+
+ case SqlDbType.SmallMoney:
+ dataType = typeof(decimal);
+ dataTypeName = "smallmoney";
+ break;
+
+ // SqlDbType.Structured not supported because it related to nested rowsets.
+
+ case SqlDbType.Text:
+ dataType = typeof(string);
+ dataTypeName = "text";
+ break;
+
+ case SqlDbType.Time:
+ dataType = typeof(TimeSpan);
+
+ if (numericPrecision.HasValue)
+ {
+ if (numericPrecision > 7)
{
- if (columnSize > 4000)
- {
- throw new ArgumentOutOfRangeException("columnSize");
- }
-
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "nvarchar({0})",
- columnSize.Value);
- }
- else
- {
- isLong = true;
-
- dataTypeName = "nvarchar(max)";
- }
- break;
-
- case SqlDbType.Real:
- dataType = typeof(float);
- dataTypeName = "real";
- break;
-
- case SqlDbType.SmallDateTime:
- dataType = typeof(DateTime);
- dataTypeName = "smalldatetime";
- break;
-
- case SqlDbType.SmallInt:
- dataType = typeof(short);
- dataTypeName = "smallint";
- break;
-
- case SqlDbType.SmallMoney:
- dataType = typeof(decimal);
- dataTypeName = "smallmoney";
- break;
-
- // SqlDbType.Structured not supported because it related to nested rowsets.
-
- case SqlDbType.Text:
- dataType = typeof(string);
- dataTypeName = "text";
- break;
-
- case SqlDbType.Time:
- dataType = typeof(TimeSpan);
-
- if (numericPrecision.HasValue)
- {
- if (numericPrecision > 7)
- {
- throw new ArgumentOutOfRangeException("numericPrecision");
- }
-
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "time({0})",
- numericPrecision.Value);
- }
- else
- {
- dataTypeName = "time";
- }
- break;
-
-
- // SqlDbType.Timestamp not supported because rowversions are not settable.
-
- case SqlDbType.TinyInt:
- dataType = typeof(byte);
- dataTypeName = "tinyint";
- break;
-
- case SqlDbType.Udt:
- if (string.IsNullOrEmpty(udtSchema))
- {
- throw new ArgumentException("udtSchema must be nonnull and nonempty for \"UDT\" columns.");
- }
- else if (string.IsNullOrEmpty(udtType))
- {
- throw new ArgumentException("udtType must be nonnull and nonempty for \"UDT\" columns.");
+ throw new ArgumentOutOfRangeException("numericPrecision");
}
- dataType = typeof(object);
- using (SqlCommandBuilder commandBuilder = new SqlCommandBuilder())
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "time({0})",
+ numericPrecision.Value);
+ }
+ else
+ {
+ dataTypeName = "time";
+ }
+
+ break;
+
+
+ // SqlDbType.Timestamp not supported because rowversions are not settable.
+
+ case SqlDbType.TinyInt:
+ dataType = typeof(byte);
+ dataTypeName = "tinyint";
+ break;
+
+ case SqlDbType.Udt:
+ if (string.IsNullOrEmpty(udtSchema))
+ {
+ throw new ArgumentException("udtSchema must be nonnull and nonempty for \"UDT\" columns.");
+ }
+
+ if (string.IsNullOrEmpty(udtType))
+ {
+ throw new ArgumentException("udtType must be nonnull and nonempty for \"UDT\" columns.");
+ }
+
+ dataType = typeof(object);
+ using (var commandBuilder = new SqlCommandBuilder())
+ {
+ dataTypeName = commandBuilder.QuoteIdentifier(udtSchema) + "." +
+ commandBuilder.QuoteIdentifier(udtType);
+ }
+
+ break;
+
+ case SqlDbType.UniqueIdentifier:
+ dataType = typeof(Guid);
+ dataTypeName = "uniqueidentifier";
+ break;
+
+ case SqlDbType.VarBinary:
+ dataType = typeof(byte[]);
+
+ if (columnSize.HasValue)
+ {
+ if (columnSize > 8000)
{
- dataTypeName = commandBuilder.QuoteIdentifier(udtSchema) + "." + commandBuilder.QuoteIdentifier(udtType);
+ throw new ArgumentOutOfRangeException("columnSize");
}
- break;
- case SqlDbType.UniqueIdentifier:
- dataType = typeof(Guid);
- dataTypeName = "uniqueidentifier";
- break;
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "varbinary({0})",
+ columnSize.Value);
+ }
+ else
+ {
+ isLong = true;
- case SqlDbType.VarBinary:
- dataType = typeof(byte[]);
+ dataTypeName = "varbinary(max)";
+ }
- if (columnSize.HasValue)
+ break;
+
+ case SqlDbType.VarChar:
+ dataType = typeof(string);
+
+ if (columnSize.HasValue)
+ {
+ if (columnSize > 8000)
{
- if (columnSize > 8000)
- {
- throw new ArgumentOutOfRangeException("columnSize");
- }
-
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "varbinary({0})",
- columnSize.Value);
+ throw new ArgumentOutOfRangeException("columnSize");
}
- else
+
+ dataTypeName = string.Format(
+ CultureInfo.InvariantCulture,
+ "varchar({0})",
+ columnSize.Value);
+ }
+ else
+ {
+ isLong = true;
+
+ dataTypeName = "varchar(max)";
+ }
+
+ break;
+
+ case SqlDbType.Variant:
+ dataType = typeof(object);
+ dataTypeName = "sql_variant";
+ break;
+
+ case SqlDbType.Xml:
+ dataType = typeof(string);
+
+ if (xmlSchemaCollectionName == null)
+ {
+ if (xmlSchemaCollectionDatabase != null || xmlSchemaCollectionOwningSchema != null)
{
- isLong = true;
-
- dataTypeName = "varbinary(max)";
+ throw new ArgumentException(
+ "xmlSchemaCollectionDatabase and xmlSchemaCollectionOwningSchema must be null if xmlSchemaCollectionName is null for \"xml\" columns.");
}
- break;
- case SqlDbType.VarChar:
- dataType = typeof(string);
-
- if (columnSize.HasValue)
+ dataTypeName = "xml";
+ }
+ else
+ {
+ if (xmlSchemaCollectionName.Length == 0)
{
- if (columnSize > 8000)
- {
- throw new ArgumentOutOfRangeException("columnSize");
- }
-
- dataTypeName = string.Format(CultureInfo.InvariantCulture,
- "varchar({0})",
- columnSize.Value);
+ throw new ArgumentException(
+ "xmlSchemaCollectionName must be nonempty or null for \"xml\" columns.");
}
- else
+
+ if (xmlSchemaCollectionDatabase != null &&
+ xmlSchemaCollectionDatabase.Length == 0)
{
- isLong = true;
-
- dataTypeName = "varchar(max)";
+ throw new ArgumentException(
+ "xmlSchemaCollectionDatabase must be null or nonempty for \"xml\" columns.");
}
- break;
- case SqlDbType.Variant:
- dataType = typeof(object);
- dataTypeName = "sql_variant";
- break;
-
- case SqlDbType.Xml:
- dataType = typeof(string);
-
- if (xmlSchemaCollectionName == null)
+ if (xmlSchemaCollectionOwningSchema != null &&
+ xmlSchemaCollectionOwningSchema.Length == 0)
{
- if (xmlSchemaCollectionDatabase != null || xmlSchemaCollectionOwningSchema != null)
- {
- throw new ArgumentException("xmlSchemaCollectionDatabase and xmlSchemaCollectionOwningSchema must be null if xmlSchemaCollectionName is null for \"xml\" columns.");
- }
-
- dataTypeName = "xml";
+ throw new ArgumentException(
+ "xmlSchemaCollectionOwningSchema must be null or nonempty for \"xml\" columns.");
}
- else
+
+ var schemaCollection = new StringBuilder("xml(");
+
+ if (xmlSchemaCollectionDatabase != null)
{
- if (xmlSchemaCollectionName.Length == 0)
- {
- throw new ArgumentException("xmlSchemaCollectionName must be nonempty or null for \"xml\" columns.");
- }
- else if (xmlSchemaCollectionDatabase != null &&
- xmlSchemaCollectionDatabase.Length == 0)
- {
- throw new ArgumentException("xmlSchemaCollectionDatabase must be null or nonempty for \"xml\" columns.");
- }
- else if (xmlSchemaCollectionOwningSchema != null &&
- xmlSchemaCollectionOwningSchema.Length == 0)
- {
- throw new ArgumentException("xmlSchemaCollectionOwningSchema must be null or nonempty for \"xml\" columns.");
- }
-
- System.Text.StringBuilder schemaCollection = new System.Text.StringBuilder("xml(");
-
- if (xmlSchemaCollectionDatabase != null)
- {
- schemaCollection.Append("[" + xmlSchemaCollectionDatabase + "]");
- }
-
- schemaCollection.Append("[" + (xmlSchemaCollectionOwningSchema == null ? SchemaName : xmlSchemaCollectionOwningSchema) + "]");
- schemaCollection.Append("[" + xmlSchemaCollectionName + "]");
-
- dataTypeName = schemaCollection.ToString();
+ schemaCollection.Append("[" + xmlSchemaCollectionDatabase + "]");
}
- break;
- default:
- throw new ArgumentOutOfRangeException("providerType");
+ schemaCollection.Append("[" + (xmlSchemaCollectionOwningSchema ?? SchemaName) + "]");
+ schemaCollection.Append("[" + xmlSchemaCollectionName + "]");
- }
+ dataTypeName = schemaCollection.ToString();
+ }
- this._schemaTable?.Rows.Add(columnName,
- _schemaTable.Rows.Count,
- columnSize,
- numericPrecision,
- numericScale,
- isUnique,
- isKey,
- "TraceServer",
- "TraceWarehouse",
- columnName,
- SchemaName,
- TableName,
- dataType,
- allowDbNull,
- providerType,
- false, // isAliased
- false, // isExpression
- false, // isIdentity,
- false, // isAutoIncrement,
- false, // isRowVersion,
- false, // isHidden,
- isLong,
- true, // isReadOnly,
- dataType,
- dataTypeName,
- xmlSchemaCollectionDatabase,
- xmlSchemaCollectionOwningSchema,
- xmlSchemaCollectionName);
+ break;
- this._columnMappings?.Add(new SqlBulkCopyColumnMapping(columnName, columnName));
+ default:
+ throw new ArgumentOutOfRangeException("providerType");
}
- #endregion
+ _schemaTable?.Rows.Add(
+ columnName,
+ _schemaTable.Rows.Count,
+ columnSize,
+ numericPrecision,
+ numericScale,
+ isUnique,
+ isKey,
+ "TraceServer",
+ "TraceWarehouse",
+ columnName,
+ SchemaName,
+ TableName,
+ dataType,
+ allowDbNull,
+ providerType,
+ false, // isAliased
+ false, // isExpression
+ false, // isIdentity,
+ false, // isAutoIncrement,
+ false, // isRowVersion,
+ false, // isHidden,
+ isLong,
+ true, // isReadOnly,
+ dataType,
+ dataTypeName,
+ xmlSchemaCollectionDatabase,
+ xmlSchemaCollectionOwningSchema,
+ xmlSchemaCollectionName);
- #region Constructors
+ _columnMappings?.Add(new SqlBulkCopyColumnMapping(columnName, columnName));
+ }
- private const string IsIdentitySchemaColumn = "IsIdentity";
+ #endregion
- private const string DataTypeNameSchemaColumn = "DataTypeName";
+ #region Constructors
- private const string XmlSchemaCollectionDatabaseSchemaColumn = "XmlSchemaCollectionDatabase";
+ private const string IsIdentitySchemaColumn = "IsIdentity";
- private const string XmlSchemaCollectionOwningSchemaSchemaColumn = "XmlSchemaCollectionOwningSchema";
+ private const string DataTypeNameSchemaColumn = "DataTypeName";
- private const string XmlSchemaCollectionNameSchemaColumn = "XmlSchemaCollectionName";
+ private const string XmlSchemaCollectionDatabaseSchemaColumn = "XmlSchemaCollectionDatabase";
- ///
- /// Constructor.
- ///
- protected BulkDataReader()
+ private const string XmlSchemaCollectionOwningSchemaSchemaColumn = "XmlSchemaCollectionOwningSchema";
+
+ private const string XmlSchemaCollectionNameSchemaColumn = "XmlSchemaCollectionName";
+
+ ///
+ /// Constructor.
+ ///
+ protected BulkDataReader()
+ {
+ _schemaTable.Locale = CultureInfo.InvariantCulture;
+
+ DataColumnCollection columns = _schemaTable.Columns;
+
+ columns.Add(SchemaTableColumn.ColumnName, typeof(string));
+ columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
+ columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
+ columns.Add(SchemaTableColumn.NumericPrecision, typeof(short));
+ columns.Add(SchemaTableColumn.NumericScale, typeof(short));
+ columns.Add(SchemaTableColumn.IsUnique, typeof(bool));
+ columns.Add(SchemaTableColumn.IsKey, typeof(bool));
+ columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
+ columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(string));
+ columns.Add(SchemaTableColumn.BaseColumnName, typeof(string));
+ columns.Add(SchemaTableColumn.BaseSchemaName, typeof(string));
+ columns.Add(SchemaTableColumn.BaseTableName, typeof(string));
+ columns.Add(SchemaTableColumn.DataType, typeof(Type));
+ columns.Add(SchemaTableColumn.AllowDBNull, typeof(bool));
+ columns.Add(SchemaTableColumn.ProviderType, typeof(int));
+ columns.Add(SchemaTableColumn.IsAliased, typeof(bool));
+ columns.Add(SchemaTableColumn.IsExpression, typeof(bool));
+ columns.Add(IsIdentitySchemaColumn, typeof(bool));
+ columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool));
+ columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(bool));
+ columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(bool));
+ columns.Add(SchemaTableColumn.IsLong, typeof(bool));
+ columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(bool));
+ columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
+ columns.Add(DataTypeNameSchemaColumn, typeof(string));
+ columns.Add(XmlSchemaCollectionDatabaseSchemaColumn, typeof(string));
+ columns.Add(XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(string));
+ columns.Add(XmlSchemaCollectionNameSchemaColumn, typeof(string));
+ }
+
+ #endregion
+
+ #region IDataReader
+
+ ///
+ /// Gets a value indicating the depth of nesting for the current row. (Inherited from .)
+ ///
+ ///
+ /// does not support nested result sets so this method always returns 0.
+ ///
+ ///
+ public int Depth => 0;
+
+ ///
+ /// Gets the number of columns in the current row. (Inherited from .)
+ ///
+ ///
+ public int FieldCount => GetSchemaTable().Rows.Count;
+
+ ///
+ /// Is the bulk copy process open?
+ ///
+ private bool _isOpen = true;
+
+ ///
+ /// Gets a value indicating whether the data reader is closed. (Inherited from .)
+ ///
+ ///
+ public bool IsClosed => !_isOpen;
+
+ ///
+ /// Gets the column located at the specified index. (Inherited from .)
+ ///
+ ///
+ /// No column with the specified index was found.
+ ///
+ ///
+ /// The zero-based index of the column to get.
+ ///
+ ///
+ /// The column located at the specified index as an .
+ ///
+ ///
+ public object this[int i] => GetValue(i);
+
+ ///
+ /// Gets the column with the specified name. (Inherited from .)
+ ///
+ ///
+ /// No column with the specified name was found.
+ ///
+ ///
+ /// The name of the column to find.
+ ///
+ ///
+ /// The column located at the specified name as an .
+ ///
+ ///
+ public object this[string name] => GetValue(GetOrdinal(name));
+
+ ///
+ /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. (Inherited from
+ /// .)
+ ///
+ ///
+ /// Always returns -1 which is the expected behaviour for statements.
+ ///
+ ///
+ public virtual int RecordsAffected => -1;
+
+ ///
+ /// Closes the . (Inherited from .)
+ ///
+ ///
+ public void Close() => _isOpen = false;
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public bool GetBoolean(int i) => (bool)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public byte GetByte(int i) => (byte)GetValue(i);
+
+ ///
+ /// Reads a stream of bytes from the specified column offset into the buffer as an array, starting at the given buffer
+ /// offset.
+ /// (Inherited from .)
+ ///
+ ///
+ /// If you pass a buffer that is null, returns the length of the row in bytes.
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The index within the field from which to start the read operation.
+ ///
+ ///
+ /// The buffer into which to read the stream of bytes.
+ ///
+ ///
+ /// The index for buffer to start the read operation.
+ ///
+ ///
+ /// The number of bytes to read.
+ ///
+ ///
+ /// The actual number of bytes read.
+ ///
+ ///
+ public long GetBytes(
+ int i,
+ long fieldOffset,
+ byte[]? buffer,
+ int bufferoffset,
+ int length)
+ {
+ var data = (byte[])GetValue(i);
+
+ if (buffer != null)
{
- this._schemaTable.Locale = System.Globalization.CultureInfo.InvariantCulture;
-
- DataColumnCollection columns = _schemaTable.Columns;
-
- columns.Add(SchemaTableColumn.ColumnName, typeof(string));
- columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
- columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
- columns.Add(SchemaTableColumn.NumericPrecision, typeof(short));
- columns.Add(SchemaTableColumn.NumericScale, typeof(short));
- columns.Add(SchemaTableColumn.IsUnique, typeof(bool));
- columns.Add(SchemaTableColumn.IsKey, typeof(bool));
- columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
- columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(string));
- columns.Add(SchemaTableColumn.BaseColumnName, typeof(string));
- columns.Add(SchemaTableColumn.BaseSchemaName, typeof(string));
- columns.Add(SchemaTableColumn.BaseTableName, typeof(string));
- columns.Add(SchemaTableColumn.DataType, typeof(Type));
- columns.Add(SchemaTableColumn.AllowDBNull, typeof(bool));
- columns.Add(SchemaTableColumn.ProviderType, typeof(int));
- columns.Add(SchemaTableColumn.IsAliased, typeof(bool));
- columns.Add(SchemaTableColumn.IsExpression, typeof(bool));
- columns.Add(BulkDataReader.IsIdentitySchemaColumn, typeof(bool));
- columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool));
- columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(bool));
- columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(bool));
- columns.Add(SchemaTableColumn.IsLong, typeof(bool));
- columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(bool));
- columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
- columns.Add(BulkDataReader.DataTypeNameSchemaColumn, typeof(string));
- columns.Add(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, typeof(string));
- columns.Add(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(string));
- columns.Add(BulkDataReader.XmlSchemaCollectionNameSchemaColumn, typeof(string));
+ Array.Copy(data, fieldOffset, buffer, bufferoffset, length);
}
- #endregion
+ return data.LongLength;
+ }
- #region IDataReader
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public char GetChar(int i)
+ {
+ char result;
- ///
- /// Gets a value indicating the depth of nesting for the current row. (Inherited from .)
- ///
- ///
- /// does not support nested result sets so this method always returns 0.
- ///
- ///
- public int Depth
+ var data = GetValue(i);
+ var dataAsChar = data as char?;
+
+ if (dataAsChar.HasValue)
{
- get { return 0; }
+ result = dataAsChar.Value;
+ }
+ else if (data is char[] dataAsCharArray &&
+ dataAsCharArray.Length == 1)
+ {
+ result = dataAsCharArray[0];
+ }
+ else if (data is string dataAsString &&
+ dataAsString.Length == 1)
+ {
+ result = dataAsString[0];
+ }
+ else
+ {
+ throw new InvalidOperationException("GetValue did not return a Char compatible type.");
}
- ///
- /// Gets the number of columns in the current row. (Inherited from .)
- ///
- ///
- public int FieldCount
+ return result;
+ }
+
+ ///
+ /// Reads a stream of characters from the specified column offset into the buffer as an array, starting at the given
+ /// buffer offset.
+ /// (Inherited from .)
+ ///
+ ///
+ /// If you pass a buffer that is null, returns the length of the row in bytes.
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The index within the field from which to start the read operation.
+ ///
+ ///
+ /// The buffer into which to read the stream of characters.
+ ///
+ ///
+ /// The index for buffer to start the read operation.
+ ///
+ ///
+ /// The number of characters to read.
+ ///
+ ///
+ /// The actual number of characters read.
+ ///
+ ///
+ public long GetChars(
+ int i,
+ long fieldoffset,
+ char[]? buffer,
+ int bufferoffset,
+ int length)
+ {
+ var data = GetValue(i);
+
+ var dataAsCharArray = data as char[];
+
+ if (data is string dataAsString)
{
- get { return GetSchemaTable().Rows.Count; }
+ dataAsCharArray = dataAsString.ToCharArray((int)fieldoffset, length);
+ }
+ else if (dataAsCharArray == null)
+ {
+ throw new InvalidOperationException("GetValue did not return either a Char array or a String.");
}
- ///
- /// Is the bulk copy process open?
- ///
- bool _isOpen = true;
-
- ///
- /// Gets a value indicating whether the data reader is closed. (Inherited from .)
- ///
- ///
- public bool IsClosed
+ if (buffer != null)
{
- get { return !_isOpen; }
+ Array.Copy(dataAsCharArray, fieldoffset, buffer, bufferoffset, length);
}
- ///
- /// Gets the column located at the specified index. (Inherited from .)
- ///
- ///
- /// No column with the specified index was found.
- ///
- ///
- /// The zero-based index of the column to get.
- ///
- ///
- /// The column located at the specified index as an .
- ///
- ///
- public object this[int i]
+ return dataAsCharArray.LongLength;
+ }
+
+ ///
+ /// Returns an IDataReader for the specified column ordinal. (Inherited from .)
+ ///
+ ///
+ /// does not support nested result sets so this method always returns null.
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The for the specified column ordinal (null).
+ ///
+ ///
+ public IDataReader GetData(int i)
+ {
+ if (i < 0 || i >= FieldCount)
{
- get { return GetValue(i); }
+ throw new ArgumentOutOfRangeException("i");
}
- ///
- /// Gets the column with the specified name. (Inherited from .)
- ///
- ///
- /// No column with the specified name was found.
- ///
- ///
- /// The name of the column to find.
- ///
- ///
- /// The column located at the specified name as an .
- ///
- ///
- public object this[string name]
+ return null!;
+ }
+
+ ///
+ /// The data type information for the specified field. (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The data type information for the specified field.
+ ///
+ ///
+ public string GetDataTypeName(int i) => GetFieldType(i).Name;
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public DateTime GetDateTime(int i) => (DateTime)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a .
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ public DateTimeOffset GetDateTimeOffset(int i) => (DateTimeOffset)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public decimal GetDecimal(int i) => (decimal)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public double GetDouble(int i) => (double)GetValue(i);
+
+ ///
+ /// Gets the information corresponding to the type of that would be returned
+ /// from .
+ /// (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The information corresponding to the type of that would be returned from
+ /// .
+ ///
+ ///
+ public Type GetFieldType(int i) => (Type)GetSchemaTable().Rows[i][SchemaTableColumn.DataType];
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public float GetFloat(int i) => (float)this[i];
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public Guid GetGuid(int i) => (Guid)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public short GetInt16(int i) => (short)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public int GetInt32(int i) => (int)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public long GetInt64(int i) => (long)GetValue(i);
+
+ ///
+ /// Gets the name for the field to find. (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The name of the field or the empty string (""), if there is no value to return.
+ ///
+ ///
+ public string GetName(int i) => (string)GetSchemaTable().Rows[i][SchemaTableColumn.ColumnName];
+
+ ///
+ /// Return the index of the named field. (Inherited from .)
+ ///
+ ///
+ /// The index of the named field was not found.
+ ///
+ ///
+ /// The name of the field to find.
+ ///
+ ///
+ /// The index of the named field.
+ ///
+ ///
+ public int GetOrdinal(string name)
+ {
+ if (name == null) // Empty strings are handled as a IndexOutOfRangeException.
{
- get { return GetValue(GetOrdinal(name)); }
+ throw new ArgumentNullException("name");
}
- ///
- /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. (Inherited from .)
- ///
- ///
- /// Always returns -1 which is the expected behaviour for statements.
- ///
- ///
- public virtual int RecordsAffected
- {
- get { return -1; }
- }
+ var result = -1;
- ///
- /// Closes the . (Inherited from .)
- ///
- ///
- public void Close()
- {
- this._isOpen = false;
- }
+ var rowCount = FieldCount;
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public bool GetBoolean(int i)
- {
- return (bool)GetValue(i);
- }
+ DataRowCollection schemaRows = GetSchemaTable().Rows;
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public byte GetByte(int i)
+ // Case sensitive search
+ for (var ordinal = 0; ordinal < rowCount; ordinal++)
{
- return (byte)GetValue(i);
- }
-
- ///
- /// Reads a stream of bytes from the specified column offset into the buffer as an array, starting at the given buffer offset.
- /// (Inherited from .)
- ///
- ///
- /// If you pass a buffer that is null, returns the length of the row in bytes.
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The index within the field from which to start the read operation.
- ///
- ///
- /// The buffer into which to read the stream of bytes.
- ///
- ///
- /// The index for buffer to start the read operation.
- ///
- ///
- /// The number of bytes to read.
- ///
- ///
- /// The actual number of bytes read.
- ///
- ///
- public long GetBytes(int i,
- long fieldOffset,
- byte[]? buffer,
- int bufferoffset,
- int length)
- {
- byte[] data = (byte[])GetValue(i);
-
- if (buffer != null)
+ if (string.Equals((string)schemaRows[ordinal][SchemaTableColumn.ColumnName], name, StringComparison.Ordinal))
{
- Array.Copy(data, fieldOffset, buffer, bufferoffset, length);
+ result = ordinal;
}
-
- return data.LongLength;
}
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public char GetChar(int i)
+ if (result == -1)
{
- char result;
-
- object data = GetValue(i);
- char? dataAsChar = data as char?;
- char[]? dataAsCharArray = data as char[];
- string? dataAsString = data as string;
-
- if (dataAsChar.HasValue)
+ // Case insensitive search.
+ for (var ordinal = 0; ordinal < rowCount; ordinal++)
{
- result = dataAsChar.Value;
- }
- else if (dataAsCharArray != null &&
- dataAsCharArray.Length == 1)
- {
- result = dataAsCharArray[0];
- }
- else if (dataAsString != null &&
- dataAsString.Length == 1)
- {
- result = dataAsString[0];
- }
- else
- {
- throw new InvalidOperationException("GetValue did not return a Char compatible type.");
- }
-
- return result;
- }
-
- ///
- /// Reads a stream of characters from the specified column offset into the buffer as an array, starting at the given buffer offset.
- /// (Inherited from .)
- ///
- ///
- /// If you pass a buffer that is null, returns the length of the row in bytes.
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The index within the field from which to start the read operation.
- ///
- ///
- /// The buffer into which to read the stream of characters.
- ///
- ///
- /// The index for buffer to start the read operation.
- ///
- ///
- /// The number of characters to read.
- ///
- ///
- /// The actual number of characters read.
- ///
- ///
- public long GetChars(int i,
- long fieldoffset,
- char[]? buffer,
- int bufferoffset,
- int length)
- {
- object data = GetValue(i);
-
- string? dataAsString = data as string;
- char[]? dataAsCharArray = data as char[];
-
- if (dataAsString != null)
- {
- dataAsCharArray = dataAsString.ToCharArray((int)fieldoffset, length);
- }
- else if (dataAsCharArray == null)
- {
- throw new InvalidOperationException("GetValue did not return either a Char array or a String.");
- }
-
- if (buffer != null)
- {
- Array.Copy(dataAsCharArray, fieldoffset, buffer, bufferoffset, length);
- }
-
- return dataAsCharArray.LongLength;
- }
-
- ///
- /// Returns an IDataReader for the specified column ordinal. (Inherited from .)
- ///
- ///
- /// does not support nested result sets so this method always returns null.
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The for the specified column ordinal (null).
- ///
- ///
- public IDataReader GetData(int i)
- {
- if (i < 0 || i >= this.FieldCount)
- {
- throw new ArgumentOutOfRangeException("i");
- }
-
- return null!;
- }
-
- ///
- /// The data type information for the specified field. (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The data type information for the specified field.
- ///
- ///
- public string GetDataTypeName(int i)
- {
- return GetFieldType(i).Name;
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public DateTime GetDateTime(int i)
- {
- return (DateTime)GetValue(i);
- }
-
- ///
- /// Gets the value of the specified column as a .
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- public DateTimeOffset GetDateTimeOffset(int i)
- {
- return (DateTimeOffset)GetValue(i);
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public decimal GetDecimal(int i)
- {
- return (decimal)GetValue(i);
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public double GetDouble(int i)
- {
- return (double)GetValue(i);
- }
-
- ///
- /// Gets the information corresponding to the type of that would be returned from .
- /// (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The information corresponding to the type of that would be returned from .
- ///
- ///
- public Type GetFieldType(int i)
- {
- return (Type)GetSchemaTable().Rows[i][SchemaTableColumn.DataType];
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public float GetFloat(int i)
- {
- return (float)this[i];
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public Guid GetGuid(int i)
- {
- return (Guid)GetValue(i);
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public short GetInt16(int i)
- {
- return (short)GetValue(i);
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public int GetInt32(int i)
- {
- return (int)GetValue(i);
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public long GetInt64(int i)
- {
- return (long)GetValue(i);
- }
-
- ///
- /// Gets the name for the field to find. (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The name of the field or the empty string (""), if there is no value to return.
- ///
- ///
- public string GetName(int i)
- {
- return (string)GetSchemaTable().Rows[i][SchemaTableColumn.ColumnName];
- }
-
- ///
- /// Return the index of the named field. (Inherited from .)
- ///
- ///
- /// The index of the named field was not found.
- ///
- ///
- /// The name of the field to find.
- ///
- ///
- /// The index of the named field.
- ///
- ///
- public int GetOrdinal(string name)
- {
- if (name == null) // Empty strings are handled as a IndexOutOfRangeException.
- {
- throw new ArgumentNullException("name");
- }
-
- int result = -1;
-
- int rowCount = FieldCount;
-
- DataRowCollection schemaRows = GetSchemaTable().Rows;
-
- // Case sensitive search
- for (int ordinal = 0; ordinal < rowCount; ordinal++)
- {
- if (String.Equals((string)schemaRows[ordinal][SchemaTableColumn.ColumnName], name, StringComparison.Ordinal))
+ if (string.Equals((string)schemaRows[ordinal][SchemaTableColumn.ColumnName], name, StringComparison.OrdinalIgnoreCase))
{
result = ordinal;
}
}
-
- if (result == -1)
- {
- // Case insensitive search.
- for (int ordinal = 0; ordinal < rowCount; ordinal++)
- {
- if (String.Equals((string)schemaRows[ordinal][SchemaTableColumn.ColumnName], name, StringComparison.OrdinalIgnoreCase))
- {
- result = ordinal;
- }
- }
- }
-
- if (result == -1)
- {
- throw new IndexOutOfRangeException(name);
- }
-
- return result;
}
- ///
- /// Returns a that describes the column metadata of the . (Inherited from .)
- ///
- ///
- /// The is closed.
- ///
- ///
- /// A that describes the column metadata.
- ///
- ///
- public DataTable GetSchemaTable()
+ if (result == -1)
{
- if (IsClosed)
- {
- throw new InvalidOperationException("The IDataReader is closed.");
- }
-
- if (_schemaTable?.Rows.Count == 0)
- {
- // Need to add the column definitions and mappings
- _schemaTable.TableName = TableName;
-
- AddSchemaTableRows();
-
- Debug.Assert(_schemaTable.Rows.Count == FieldCount);
- }
-
- return _schemaTable!;
+ throw new IndexOutOfRangeException(name);
}
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public string GetString(int i)
- {
- return (string)GetValue(i);
- }
-
- ///
- /// Gets the value of the specified column as a .
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- public TimeSpan GetTimeSpan(int i)
- {
- return (TimeSpan)GetValue(i);
- }
-
- ///
- /// Gets the value of the specified column as a . (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// The value of the column.
- ///
- ///
- public abstract object GetValue(int i);
-
- ///
- /// Populates an array of objects with the column values of the current record. (Inherited from .)
- ///
- ///
- /// was null.
- ///
- ///
- /// An array of to copy the attribute fields into.
- ///
- ///
- /// The number of instances of in the array.
- ///
- ///
- public int GetValues(object[] values)
- {
- if (values == null)
- {
- throw new ArgumentNullException("values");
- }
-
- int fieldCount = Math.Min(FieldCount, values.Length);
-
- for (int i = 0; i < fieldCount; i++)
- {
- values[i] = GetValue(i);
- }
-
- return fieldCount;
- }
-
- ///
- /// Return whether the specified field is set to null. (Inherited from .)
- ///
- ///
- /// The index passed was outside the range of 0 through .
- ///
- ///
- /// The zero-based column ordinal.
- ///
- ///
- /// True if the specified field is set to null; otherwise, false.
- ///
- ///
- public bool IsDBNull(int i)
- {
- object data = GetValue(i);
-
- return data == null || Convert.IsDBNull(data);
- }
-
- ///
- /// Advances the data reader to the next result, when reading the results of batch SQL statements. (Inherited from .)
- ///
- ///
- /// for returns a single result set so false is always returned.
- ///
- ///
- /// True if there are more rows; otherwise, false. for returns a single result set so false is always returned.
- ///
- ///
- public bool NextResult()
- {
- return false;
- }
-
- ///
- /// Advances the to the next record. (Inherited from .)
- ///
- ///
- /// True if there are more rows; otherwise, false.
- ///
- ///
- public abstract bool Read();
-
- #endregion
-
- #region IDisposable
-
- ///
- /// Has the object been disposed?
- ///
- bool _disposed = false;
-
- ///
- /// Dispose of any disposable and expensive resources.
- ///
- ///
- /// Is this call the result of a call?
- ///
- protected virtual void Dispose(bool disposing)
- {
- if (!this._disposed)
- {
- this._disposed = true;
-
- if (disposing)
- {
- if (_schemaTable != null)
- {
- _schemaTable.Dispose();
- this._schemaTable = null;
- }
-
- this._columnMappings = null;
-
- this._isOpen = false;
-
- GC.SuppressFinalize(this);
- }
- }
- }
-
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. (Inherited from .)
- ///
- ///
- public void Dispose()
- {
- Dispose(true);
- }
-
- ///
- /// Finalizer
- ///
- ///
- /// has no unmanaged resources but a subclass may thus a finalizer is required.
- ///
- ~BulkDataReader()
- {
- Dispose(false);
- }
-
- #endregion
-
+ return result;
}
+
+ ///
+ /// Returns a that describes the column metadata of the . (Inherited
+ /// from .)
+ ///
+ ///
+ /// The is closed.
+ ///
+ ///
+ /// A that describes the column metadata.
+ ///
+ ///
+ public DataTable GetSchemaTable()
+ {
+ if (IsClosed)
+ {
+ throw new InvalidOperationException("The IDataReader is closed.");
+ }
+
+ if (_schemaTable?.Rows.Count == 0)
+ {
+ // Need to add the column definitions and mappings
+ _schemaTable.TableName = TableName;
+
+ AddSchemaTableRows();
+
+ Debug.Assert(_schemaTable.Rows.Count == FieldCount);
+ }
+
+ return _schemaTable!;
+ }
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public string GetString(int i) => (string)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a .
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ public TimeSpan GetTimeSpan(int i) => (TimeSpan)GetValue(i);
+
+ ///
+ /// Gets the value of the specified column as a . (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// The value of the column.
+ ///
+ ///
+ public abstract object GetValue(int i);
+
+ ///
+ /// Populates an array of objects with the column values of the current record. (Inherited from
+ /// .)
+ ///
+ ///
+ /// was null.
+ ///
+ ///
+ /// An array of to copy the attribute fields into.
+ ///
+ ///
+ /// The number of instances of in the array.
+ ///
+ ///
+ public int GetValues(object[] values)
+ {
+ if (values == null)
+ {
+ throw new ArgumentNullException("values");
+ }
+
+ var fieldCount = Math.Min(FieldCount, values.Length);
+
+ for (var i = 0; i < fieldCount; i++)
+ {
+ values[i] = GetValue(i);
+ }
+
+ return fieldCount;
+ }
+
+ ///
+ /// Return whether the specified field is set to null. (Inherited from .)
+ ///
+ ///
+ /// The index passed was outside the range of 0 through .
+ ///
+ ///
+ /// The zero-based column ordinal.
+ ///
+ ///
+ /// True if the specified field is set to null; otherwise, false.
+ ///
+ ///
+ public bool IsDBNull(int i)
+ {
+ var data = GetValue(i);
+
+ return data == null || Convert.IsDBNull(data);
+ }
+
+ ///
+ /// Advances the data reader to the next result, when reading the results of batch SQL statements. (Inherited from
+ /// .)
+ ///
+ ///
+ /// for returns a single result set so false is always returned.
+ ///
+ ///
+ /// True if there are more rows; otherwise, false. for returns a
+ /// single result set so false is always returned.
+ ///
+ ///
+ public bool NextResult() => false;
+
+ ///
+ /// Advances the to the next record. (Inherited from .)
+ ///
+ ///
+ /// True if there are more rows; otherwise, false.
+ ///
+ ///
+ public abstract bool Read();
+
+ #endregion
+
+ #region IDisposable
+
+ ///
+ /// Has the object been disposed?
+ ///
+ private bool _disposed;
+
+ ///
+ /// Dispose of any disposable and expensive resources.
+ ///
+ ///
+ /// Is this call the result of a call?
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ _disposed = true;
+
+ if (disposing)
+ {
+ if (_schemaTable != null)
+ {
+ _schemaTable.Dispose();
+ _schemaTable = null;
+ }
+
+ _columnMappings = null;
+
+ _isOpen = false;
+
+ GC.SuppressFinalize(this);
+ }
+ }
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. (Inherited
+ /// from .)
+ ///
+ ///
+ public void Dispose() => Dispose(true);
+
+ ///
+ /// Finalizer
+ ///
+ ///
+ /// has no unmanaged resources but a subclass may thus a finalizer is required.
+ ///
+ ~BulkDataReader() => Dispose(false);
+
+ #endregion
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/MicrosoftSqlSyntaxProviderBase.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/MicrosoftSqlSyntaxProviderBase.cs
index 4856e1e117..7256317c15 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/MicrosoftSqlSyntaxProviderBase.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/MicrosoftSqlSyntaxProviderBase.cs
@@ -6,216 +6,218 @@ using Umbraco.Cms.Core.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions;
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
-namespace Umbraco.Cms.Persistence.SqlServer.Services
+namespace Umbraco.Cms.Persistence.SqlServer.Services;
+
+///
+/// Abstract class for defining MS sql implementations
+///
+///
+public abstract class MicrosoftSqlSyntaxProviderBase : SqlSyntaxProviderBase
+ where TSyntax : ISqlSyntaxProvider
{
- ///
- /// Abstract class for defining MS sql implementations
- ///
- ///
- public abstract class MicrosoftSqlSyntaxProviderBase : SqlSyntaxProviderBase
- where TSyntax : ISqlSyntaxProvider
+ private readonly ILogger _logger;
+
+ protected MicrosoftSqlSyntaxProviderBase()
{
- private readonly ILogger _logger;
+ _logger = StaticApplicationLogging.CreateLogger();
- protected MicrosoftSqlSyntaxProviderBase()
+ AutoIncrementDefinition = "IDENTITY(1,1)";
+ GuidColumnDefinition = "UniqueIdentifier";
+ RealColumnDefinition = "FLOAT";
+ BoolColumnDefinition = "BIT";
+ DecimalColumnDefinition = "DECIMAL(38,6)";
+ TimeColumnDefinition = "TIME"; //SQLSERVER 2008+
+ BlobColumnDefinition = "VARBINARY(MAX)";
+ }
+
+ public override string RenameTable => "sp_rename '{0}', '{1}'";
+
+ public override string AddColumn => "ALTER TABLE {0} ADD {1}";
+
+ public override string GetQuotedTableName(string? tableName)
+ {
+ if (tableName?.Contains(".") == false)
{
- _logger = StaticApplicationLogging.CreateLogger();
-
- AutoIncrementDefinition = "IDENTITY(1,1)";
- GuidColumnDefinition = "UniqueIdentifier";
- RealColumnDefinition = "FLOAT";
- BoolColumnDefinition = "BIT";
- DecimalColumnDefinition = "DECIMAL(38,6)";
- TimeColumnDefinition = "TIME"; //SQLSERVER 2008+
- BlobColumnDefinition = "VARBINARY(MAX)";
+ return $"[{tableName}]";
}
- public override string RenameTable => "sp_rename '{0}', '{1}'";
+ var tableNameParts = tableName?.Split(Core.Constants.CharArrays.Period, 2);
+ return $"[{tableNameParts?[0]}].[{tableNameParts?[1]}]";
+ }
- public override string AddColumn => "ALTER TABLE {0} ADD {1}";
+ public override string GetQuotedColumnName(string? columnName) => $"[{columnName}]";
- public override string GetQuotedTableName(string? tableName)
+ public override string GetQuotedName(string? name) => $"[{name}]";
+
+ public override string GetStringColumnEqualComparison(string column, int paramIndex, TextColumnType columnType)
+ {
+ switch (columnType)
{
- if (tableName?.Contains(".") == false)
- return $"[{tableName}]";
+ case TextColumnType.NVarchar:
+ return base.GetStringColumnEqualComparison(column, paramIndex, columnType);
+ case TextColumnType.NText:
+ //MSSQL doesn't allow for = comparison with NText columns but allows this syntax
+ return $"{column} LIKE @{paramIndex}";
+ default:
+ throw new ArgumentOutOfRangeException(nameof(columnType));
+ }
+ }
- var tableNameParts = tableName?.Split(Cms.Core.Constants.CharArrays.Period, 2);
- return $"[{tableNameParts?[0]}].[{tableNameParts?[1]}]";
+ public override string GetStringColumnWildcardComparison(string column, int paramIndex, TextColumnType columnType)
+ {
+ switch (columnType)
+ {
+ case TextColumnType.NVarchar:
+ return base.GetStringColumnWildcardComparison(column, paramIndex, columnType);
+ case TextColumnType.NText:
+ //MSSQL doesn't allow for upper methods with NText columns
+ return $"{column} LIKE @{paramIndex}";
+ default:
+ throw new ArgumentOutOfRangeException(nameof(columnType));
+ }
+ }
+
+ ///
+ /// This uses a the DbTypeMap created and custom mapping to resolve the SqlDbType
+ ///
+ ///
+ ///
+ public virtual SqlDbType GetSqlDbType(Type clrType)
+ {
+ DbType dbType = DbTypeMap.ColumnDbTypeMap[clrType];
+ return GetSqlDbType(dbType);
+ }
+
+ ///
+ /// Returns the mapped SqlDbType for the DbType specified
+ ///
+ ///
+ ///
+ public virtual SqlDbType GetSqlDbType(DbType dbType)
+ {
+ SqlDbType sqlDbType;
+
+ //SEE: https://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
+ // and https://msdn.microsoft.com/en-us/library/yy6y35y8%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
+ switch (dbType)
+ {
+ case DbType.AnsiString:
+ sqlDbType = SqlDbType.VarChar;
+ break;
+ case DbType.Binary:
+ sqlDbType = SqlDbType.VarBinary;
+ break;
+ case DbType.Byte:
+ sqlDbType = SqlDbType.TinyInt;
+ break;
+ case DbType.Boolean:
+ sqlDbType = SqlDbType.Bit;
+ break;
+ case DbType.Currency:
+ sqlDbType = SqlDbType.Money;
+ break;
+ case DbType.Date:
+ sqlDbType = SqlDbType.Date;
+ break;
+ case DbType.DateTime:
+ sqlDbType = SqlDbType.DateTime;
+ break;
+ case DbType.Decimal:
+ sqlDbType = SqlDbType.Decimal;
+ break;
+ case DbType.Double:
+ sqlDbType = SqlDbType.Float;
+ break;
+ case DbType.Guid:
+ sqlDbType = SqlDbType.UniqueIdentifier;
+ break;
+ case DbType.Int16:
+ sqlDbType = SqlDbType.SmallInt;
+ break;
+ case DbType.Int32:
+ sqlDbType = SqlDbType.Int;
+ break;
+ case DbType.Int64:
+ sqlDbType = SqlDbType.BigInt;
+ break;
+ case DbType.Object:
+ sqlDbType = SqlDbType.Variant;
+ break;
+ case DbType.SByte:
+ throw new NotSupportedException("Inferring a SqlDbType from SByte is not supported.");
+ case DbType.Single:
+ sqlDbType = SqlDbType.Real;
+ break;
+ case DbType.String:
+ sqlDbType = SqlDbType.NVarChar;
+ break;
+ case DbType.Time:
+ sqlDbType = SqlDbType.Time;
+ break;
+ case DbType.UInt16:
+ throw new NotSupportedException("Inferring a SqlDbType from UInt16 is not supported.");
+ case DbType.UInt32:
+ throw new NotSupportedException("Inferring a SqlDbType from UInt32 is not supported.");
+ case DbType.UInt64:
+ throw new NotSupportedException("Inferring a SqlDbType from UInt64 is not supported.");
+ case DbType.VarNumeric:
+ throw new NotSupportedException("Inferring a VarNumeric from UInt64 is not supported.");
+ case DbType.AnsiStringFixedLength:
+ sqlDbType = SqlDbType.Char;
+ break;
+ case DbType.StringFixedLength:
+ sqlDbType = SqlDbType.NChar;
+ break;
+ case DbType.Xml:
+ sqlDbType = SqlDbType.Xml;
+ break;
+ case DbType.DateTime2:
+ sqlDbType = SqlDbType.DateTime2;
+ break;
+ case DbType.DateTimeOffset:
+ sqlDbType = SqlDbType.DateTimeOffset;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
}
- public override string GetQuotedColumnName(string? columnName) => $"[{columnName}]";
+ return sqlDbType;
+ }
- public override string GetQuotedName(string? name) => $"[{name}]";
+ public override void HandleCreateTable(IDatabase database, TableDefinition tableDefinition, bool skipKeysAndIndexes = false)
+ {
+ var createSql = Format(tableDefinition);
+ var createPrimaryKeySql = FormatPrimaryKey(tableDefinition);
+ List foreignSql = Format(tableDefinition.ForeignKeys);
- public override string GetStringColumnEqualComparison(string column, int paramIndex, TextColumnType columnType)
+ _logger.LogInformation("Create table:\n {Sql}", createSql);
+ database.Execute(new Sql(createSql));
+
+ if (skipKeysAndIndexes)
{
- switch (columnType)
- {
- case TextColumnType.NVarchar:
- return base.GetStringColumnEqualComparison(column, paramIndex, columnType);
- case TextColumnType.NText:
- //MSSQL doesn't allow for = comparison with NText columns but allows this syntax
- return $"{column} LIKE @{paramIndex}";
- default:
- throw new ArgumentOutOfRangeException(nameof(columnType));
- }
+ return;
}
- public override string GetStringColumnWildcardComparison(string column, int paramIndex, TextColumnType columnType)
+ //If any statements exists for the primary key execute them here
+ if (string.IsNullOrEmpty(createPrimaryKeySql) == false)
{
- switch (columnType)
- {
- case TextColumnType.NVarchar:
- return base.GetStringColumnWildcardComparison(column, paramIndex, columnType);
- case TextColumnType.NText:
- //MSSQL doesn't allow for upper methods with NText columns
- return $"{column} LIKE @{paramIndex}";
- default:
- throw new ArgumentOutOfRangeException(nameof(columnType));
- }
+ _logger.LogInformation("Create Primary Key:\n {Sql}", createPrimaryKeySql);
+ database.Execute(new Sql(createPrimaryKeySql));
}
- ///
- /// This uses a the DbTypeMap created and custom mapping to resolve the SqlDbType
- ///
- ///
- ///
- public virtual SqlDbType GetSqlDbType(Type clrType)
+ List indexSql = Format(tableDefinition.Indexes);
+ //Loop through index statements and execute sql
+ foreach (var sql in indexSql)
{
- var dbType = DbTypeMap.ColumnDbTypeMap[clrType];
- return GetSqlDbType(dbType);
+ _logger.LogInformation("Create Index:\n {Sql}", sql);
+ database.Execute(new Sql(sql));
}
- ///
- /// Returns the mapped SqlDbType for the DbType specified
- ///
- ///
- ///
- public virtual SqlDbType GetSqlDbType(DbType dbType)
+ //Loop through foreignkey statements and execute sql
+ foreach (var sql in foreignSql)
{
- SqlDbType sqlDbType;
-
- //SEE: https://msdn.microsoft.com/en-us/library/cc716729(v=vs.110).aspx
- // and https://msdn.microsoft.com/en-us/library/yy6y35y8%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
- switch (dbType)
- {
- case DbType.AnsiString:
- sqlDbType = SqlDbType.VarChar;
- break;
- case DbType.Binary:
- sqlDbType = SqlDbType.VarBinary;
- break;
- case DbType.Byte:
- sqlDbType = SqlDbType.TinyInt;
- break;
- case DbType.Boolean:
- sqlDbType = SqlDbType.Bit;
- break;
- case DbType.Currency:
- sqlDbType = SqlDbType.Money;
- break;
- case DbType.Date:
- sqlDbType = SqlDbType.Date;
- break;
- case DbType.DateTime:
- sqlDbType = SqlDbType.DateTime;
- break;
- case DbType.Decimal:
- sqlDbType = SqlDbType.Decimal;
- break;
- case DbType.Double:
- sqlDbType = SqlDbType.Float;
- break;
- case DbType.Guid:
- sqlDbType = SqlDbType.UniqueIdentifier;
- break;
- case DbType.Int16:
- sqlDbType = SqlDbType.SmallInt;
- break;
- case DbType.Int32:
- sqlDbType = SqlDbType.Int;
- break;
- case DbType.Int64:
- sqlDbType = SqlDbType.BigInt;
- break;
- case DbType.Object:
- sqlDbType = SqlDbType.Variant;
- break;
- case DbType.SByte:
- throw new NotSupportedException("Inferring a SqlDbType from SByte is not supported.");
- case DbType.Single:
- sqlDbType = SqlDbType.Real;
- break;
- case DbType.String:
- sqlDbType = SqlDbType.NVarChar;
- break;
- case DbType.Time:
- sqlDbType = SqlDbType.Time;
- break;
- case DbType.UInt16:
- throw new NotSupportedException("Inferring a SqlDbType from UInt16 is not supported.");
- case DbType.UInt32:
- throw new NotSupportedException("Inferring a SqlDbType from UInt32 is not supported.");
- case DbType.UInt64:
- throw new NotSupportedException("Inferring a SqlDbType from UInt64 is not supported.");
- case DbType.VarNumeric:
- throw new NotSupportedException("Inferring a VarNumeric from UInt64 is not supported.");
- case DbType.AnsiStringFixedLength:
- sqlDbType = SqlDbType.Char;
- break;
- case DbType.StringFixedLength:
- sqlDbType = SqlDbType.NChar;
- break;
- case DbType.Xml:
- sqlDbType = SqlDbType.Xml;
- break;
- case DbType.DateTime2:
- sqlDbType = SqlDbType.DateTime2;
- break;
- case DbType.DateTimeOffset:
- sqlDbType = SqlDbType.DateTimeOffset;
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- return sqlDbType;
- }
-
- public override void HandleCreateTable(IDatabase database, TableDefinition tableDefinition, bool skipKeysAndIndexes = false)
- {
- var createSql = Format(tableDefinition);
- var createPrimaryKeySql = FormatPrimaryKey(tableDefinition);
- List foreignSql = Format(tableDefinition.ForeignKeys);
-
- _logger.LogInformation("Create table:\n {Sql}", createSql);
- database.Execute(new Sql(createSql));
-
- if (skipKeysAndIndexes)
- {
- return;
- }
-
- //If any statements exists for the primary key execute them here
- if (string.IsNullOrEmpty(createPrimaryKeySql) == false)
- {
- _logger.LogInformation("Create Primary Key:\n {Sql}", createPrimaryKeySql);
- database.Execute(new Sql(createPrimaryKeySql));
- }
-
- List indexSql = Format(tableDefinition.Indexes);
- //Loop through index statements and execute sql
- foreach (var sql in indexSql)
- {
- _logger.LogInformation("Create Index:\n {Sql}", sql);
- database.Execute(new Sql(sql));
- }
-
- //Loop through foreignkey statements and execute sql
- foreach (var sql in foreignSql)
- {
- _logger.LogInformation("Create Foreign Key:\n {Sql}", sql);
- database.Execute(new Sql(sql));
- }
+ _logger.LogInformation("Create Foreign Key:\n {Sql}", sql);
+ database.Execute(new Sql(sql));
}
}
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/PocoDataDataReader.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/PocoDataDataReader.cs
index 8a05e78258..2b9d35b959 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/PocoDataDataReader.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/PocoDataDataReader.cs
@@ -4,142 +4,166 @@ using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions;
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
-namespace Umbraco.Cms.Persistence.SqlServer.Services
+namespace Umbraco.Cms.Persistence.SqlServer.Services;
+
+///
+/// A data reader used for reading collections of PocoData entity types
+///
+///
+/// We are using a custom data reader so that tons of memory is not consumed when rebuilding this table, previously
+/// we'd generate SQL insert statements, but we'd have to put all of the XML structures into memory first.
+/// Alternatively
+/// we can use .net's DataTable, but this also requires putting everything into memory. By using a DataReader we don't
+/// have to
+/// store every content item and it's XML structure in memory to get it into the DB, we can stream it into the db with
+/// this
+/// reader.
+///
+internal class PocoDataDataReader : BulkDataReader
+ where TSyntax : ISqlSyntaxProvider
{
- ///
- /// A data reader used for reading collections of PocoData entity types
- ///
- ///
- /// We are using a custom data reader so that tons of memory is not consumed when rebuilding this table, previously
- /// we'd generate SQL insert statements, but we'd have to put all of the XML structures into memory first. Alternatively
- /// we can use .net's DataTable, but this also requires putting everything into memory. By using a DataReader we don't have to
- /// store every content item and it's XML structure in memory to get it into the DB, we can stream it into the db with this
- /// reader.
- ///
- internal class PocoDataDataReader : BulkDataReader
- where TSyntax : ISqlSyntaxProvider
+ private readonly ColumnDefinition[] _columnDefinitions;
+ private readonly IEnumerator _enumerator;
+ private readonly PocoColumn[] _readerColumns;
+ private readonly MicrosoftSqlSyntaxProviderBase _sqlSyntaxProvider;
+ private readonly TableDefinition _tableDefinition;
+ private int _recordsAffected = -1;
+
+ public PocoDataDataReader(
+ IEnumerable dataSource,
+ PocoData pd,
+ MicrosoftSqlSyntaxProviderBase sqlSyntaxProvider)
{
- private readonly MicrosoftSqlSyntaxProviderBase _sqlSyntaxProvider;
- private readonly TableDefinition _tableDefinition;
- private readonly PocoColumn[] _readerColumns;
- private readonly IEnumerator _enumerator;
- private readonly ColumnDefinition[] _columnDefinitions;
- private int _recordsAffected = -1;
-
- public PocoDataDataReader(
- IEnumerable dataSource,
- PocoData pd,
- MicrosoftSqlSyntaxProviderBase sqlSyntaxProvider)
+ if (dataSource == null)
{
- if (dataSource == null) throw new ArgumentNullException(nameof(dataSource));
- if (sqlSyntaxProvider == null) throw new ArgumentNullException(nameof(sqlSyntaxProvider));
-
- _tableDefinition = DefinitionFactory.GetTableDefinition(pd.Type, sqlSyntaxProvider);
- if (_tableDefinition == null) throw new InvalidOperationException("No table definition found for type " + pd.Type);
-
- // only real columns, exclude result/computed columns
- // Like NPoco does: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L59
- _readerColumns = pd.Columns
- .Where(x => x.Value.ResultColumn == false && x.Value.ComputedColumn == false)
- .Select(x => x.Value)
- .ToArray();
-
- _sqlSyntaxProvider = sqlSyntaxProvider;
- _enumerator = dataSource.GetEnumerator();
- _columnDefinitions = _tableDefinition.Columns.ToArray();
-
+ throw new ArgumentNullException(nameof(dataSource));
}
- protected override string SchemaName => _tableDefinition.SchemaName;
-
- protected override string TableName => _tableDefinition.Name;
-
- public override int RecordsAffected => _recordsAffected <= 0 ? -1 : _recordsAffected;
-
- ///
- /// This will automatically add the schema rows based on the Poco table definition and the columns passed in
- ///
- protected override void AddSchemaTableRows()
+ if (sqlSyntaxProvider == null)
{
- //var colNames = _readerColumns.Select(x => x.ColumnName).ToArray();
- //foreach (var col in _columnDefinitions.Where(x => colNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase)))
- foreach (var col in _columnDefinitions)
+ throw new ArgumentNullException(nameof(sqlSyntaxProvider));
+ }
+
+ _tableDefinition = DefinitionFactory.GetTableDefinition(pd.Type, sqlSyntaxProvider);
+ if (_tableDefinition == null)
+ {
+ throw new InvalidOperationException("No table definition found for type " + pd.Type);
+ }
+
+ // only real columns, exclude result/computed columns
+ // Like NPoco does: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L59
+ _readerColumns = pd.Columns
+ .Where(x => x.Value.ResultColumn == false && x.Value.ComputedColumn == false)
+ .Select(x => x.Value)
+ .ToArray();
+
+ _sqlSyntaxProvider = sqlSyntaxProvider;
+ _enumerator = dataSource.GetEnumerator();
+ _columnDefinitions = _tableDefinition.Columns.ToArray();
+ }
+
+ protected override string SchemaName => _tableDefinition.SchemaName;
+
+ protected override string TableName => _tableDefinition.Name;
+
+ public override int RecordsAffected => _recordsAffected <= 0 ? -1 : _recordsAffected;
+
+ ///
+ /// This will automatically add the schema rows based on the Poco table definition and the columns passed in
+ ///
+ protected override void AddSchemaTableRows()
+ {
+ //var colNames = _readerColumns.Select(x => x.ColumnName).ToArray();
+ //foreach (var col in _columnDefinitions.Where(x => colNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase)))
+ foreach (ColumnDefinition col in _columnDefinitions)
+ {
+ SqlDbType sqlDbType;
+ if (col.CustomDbType.HasValue)
{
- SqlDbType sqlDbType;
- if (col.CustomDbType.HasValue)
+ //get the SqlDbType from the 'special type'
+ switch (col.CustomDbType)
{
- //get the SqlDbType from the 'special type'
- switch (col.CustomDbType)
- {
- case var x when x == SpecialDbType.NTEXT:
- sqlDbType = SqlDbType.NText;
- break;
- case var x when x == SpecialDbType.NCHAR:
- sqlDbType = SqlDbType.NChar;
- break;
- case var x when x == SpecialDbType.NVARCHARMAX:
- sqlDbType = SqlDbType.NVarChar;
- break;
- default:
- throw new ArgumentOutOfRangeException("The custom DB type " + col.CustomDbType + " is not supported for bulk import statements.");
- }
+ case var x when x == SpecialDbType.NTEXT:
+ sqlDbType = SqlDbType.NText;
+ break;
+ case var x when x == SpecialDbType.NCHAR:
+ sqlDbType = SqlDbType.NChar;
+ break;
+ case var x when x == SpecialDbType.NVARCHARMAX:
+ sqlDbType = SqlDbType.NVarChar;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException("The custom DB type " + col.CustomDbType +
+ " is not supported for bulk import statements.");
}
- else if (col.Type.HasValue)
- {
- //get the SqlDbType from the DbType
- sqlDbType = _sqlSyntaxProvider.GetSqlDbType(col.Type.Value);
- }
- else
- {
- //get the SqlDbType from the CLR type
- sqlDbType = _sqlSyntaxProvider.GetSqlDbType(col.PropertyType);
- }
-
- AddSchemaTableRow(
- col.Name,
- col.Size > 0 ? (int?)col.Size : null,
- col.Precision > 0 ? (short?)col.Precision : null,
- null, col.IsUnique, col.IsIdentity, col.IsNullable, sqlDbType,
- null, null, null, null, null);
}
- }
-
- ///
- /// Get the value from the column index for the current object
- ///
- ///
- ///
- public override object GetValue(int i)
- {
- return _enumerator.Current == null ? null! : _readerColumns[i].GetValue(_enumerator.Current);
- }
-
- ///
- /// Advance the cursor
- ///
- ///
- public override bool Read()
- {
- var result = _enumerator.MoveNext();
- if (result)
+ else if (col.Type.HasValue)
{
- if (_recordsAffected == -1)
- _recordsAffected = 0;
- _recordsAffected++;
+ //get the SqlDbType from the DbType
+ sqlDbType = _sqlSyntaxProvider.GetSqlDbType(col.Type.Value);
}
- return result;
+ else
+ {
+ //get the SqlDbType from the CLR type
+ sqlDbType = _sqlSyntaxProvider.GetSqlDbType(col.PropertyType);
+ }
+
+ AddSchemaTableRow(
+ col.Name,
+ col.Size > 0 ? col.Size : null,
+ col.Precision > 0 ? (short?)col.Precision : null,
+ null,
+ col.IsUnique,
+ col.IsIdentity,
+ col.IsNullable,
+ sqlDbType,
+ null,
+ null,
+ null,
+ null,
+ null);
+ }
+ }
+
+ ///
+ /// Get the value from the column index for the current object
+ ///
+ ///
+ ///
+ public override object GetValue(int i) =>
+ _enumerator.Current == null ? null! : _readerColumns[i].GetValue(_enumerator.Current);
+
+ ///
+ /// Advance the cursor
+ ///
+ ///
+ public override bool Read()
+ {
+ var result = _enumerator.MoveNext();
+ if (result)
+ {
+ if (_recordsAffected == -1)
+ {
+ _recordsAffected = 0;
+ }
+
+ _recordsAffected++;
}
- ///
- /// Ensure the enumerator is disposed
- ///
- ///
- protected override void Dispose(bool disposing)
- {
- base.Dispose(disposing);
+ return result;
+ }
- if (disposing)
- _enumerator.Dispose();
+ ///
+ /// Ensure the enumerator is disposed
+ ///
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ if (disposing)
+ {
+ _enumerator.Dispose();
}
}
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs
index cf74a8549f..0dbc62fb49 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlAzureDatabaseProviderMetadata.cs
@@ -6,13 +6,13 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Persistence.SqlServer.Services;
///
-/// Provider metadata for SQL Azure
+/// Provider metadata for SQL Azure
///
[DataContract]
public class SqlAzureDatabaseProviderMetadata : IDatabaseProviderMetadata
{
///
- public Guid Id => new ("7858e827-8951-4fe0-a7fe-6883011b1f1b");
+ public Guid Id => new("7858e827-8951-4fe0-a7fe-6883011b1f1b");
///
public int SortOrder => 3;
@@ -59,37 +59,49 @@ public class SqlAzureDatabaseProviderMetadata : IDatabaseProviderMetadata
var password = databaseModel.Password;
if (server.Contains(".") && ServerStartsWithTcp(server) == false)
+ {
server = $"tcp:{server}";
+ }
if (server.Contains(".") == false && ServerStartsWithTcp(server))
{
- string serverName = server.Contains(",")
+ var serverName = server.Contains(",")
? server.Substring(0, server.IndexOf(",", StringComparison.Ordinal))
: server;
var portAddition = string.Empty;
if (server.Contains(","))
+ {
portAddition = server.Substring(server.IndexOf(",", StringComparison.Ordinal));
+ }
server = $"{serverName}.database.windows.net{portAddition}";
}
if (ServerStartsWithTcp(server) == false)
+ {
server = $"tcp:{server}.database.windows.net";
+ }
if (server.Contains(",") == false)
+ {
server = $"{server},1433";
+ }
if (user.Contains("@") == false)
{
var userDomain = server;
if (ServerStartsWithTcp(server))
+ {
userDomain = userDomain.Substring(userDomain.IndexOf(":", StringComparison.Ordinal) + 1);
+ }
if (userDomain.Contains("."))
+ {
userDomain = userDomain.Substring(0, userDomain.IndexOf(".", StringComparison.Ordinal));
+ }
user = $"{user}@{userDomain}";
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs
index 1741b8ffe1..30a503e5f9 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlLocalDbDatabaseProviderMetadata.cs
@@ -7,13 +7,13 @@ using Umbraco.Cms.Infrastructure.Persistence;
namespace Umbraco.Cms.Persistence.SqlServer.Services;
///
-/// Provider metadata for SQL Server LocalDb
+/// Provider metadata for SQL Server LocalDb
///
[DataContract]
public class SqlLocalDbDatabaseProviderMetadata : IDatabaseProviderMetadata
{
///
- public Guid Id => new ("05a7e9ed-aa6a-43af-a309-63422c87c675");
+ public Guid Id => new("05a7e9ed-aa6a-43af-a309-63422c87c675");
///
public int SortOrder => 1;
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerBulkSqlInsertProvider.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerBulkSqlInsertProvider.cs
index cfd30bbd90..dbaab82ad4 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerBulkSqlInsertProvider.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerBulkSqlInsertProvider.cs
@@ -1,74 +1,85 @@
using System.Data;
+using System.Data.Common;
using Microsoft.Data.SqlClient;
using NPoco;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Extensions;
-namespace Umbraco.Cms.Persistence.SqlServer.Services
+namespace Umbraco.Cms.Persistence.SqlServer.Services;
+
+///
+/// A bulk sql insert provider for Sql Server
+///
+public class SqlServerBulkSqlInsertProvider : IBulkSqlInsertProvider
{
- ///
- /// A bulk sql insert provider for Sql Server
- ///
- public class SqlServerBulkSqlInsertProvider : IBulkSqlInsertProvider
+ public string ProviderName => Constants.ProviderName;
+
+ public int BulkInsertRecords(IUmbracoDatabase database, IEnumerable records)
{
- public string ProviderName => Constants.ProviderName;
-
- public int BulkInsertRecords(IUmbracoDatabase database, IEnumerable records)
+ T[] recordsA = records.ToArray();
+ if (recordsA.Length == 0)
{
- var recordsA = records.ToArray();
- if (recordsA.Length == 0) return 0;
-
- var pocoData = database.PocoDataFactory.ForType(typeof(T));
- if (pocoData == null) throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
-
- return BulkInsertRecordsSqlServer(database, pocoData, recordsA);
+ return 0;
}
- ///
- /// Bulk-insert records using SqlServer BulkCopy method.
- ///
- /// The type of the records.
- /// The database.
- /// The PocoData object corresponding to the record's type.
- /// The records.
- /// The number of records that were inserted.
- private int BulkInsertRecordsSqlServer(IUmbracoDatabase database, PocoData pocoData, IEnumerable records)
+ PocoData? pocoData = database.PocoDataFactory.ForType(typeof(T));
+ if (pocoData == null)
{
- // TODO: The main reason this exists is because the NPoco InsertBulk method doesn't return the number of items.
- // It is worth investigating the performance of this vs NPoco's because we use a custom BulkDataReader
- // which in theory should be more efficient than NPocos way of building up an in-memory DataTable.
+ throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
+ }
- // create command against the original database.Connection
- using (var command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty))
+ return BulkInsertRecordsSqlServer(database, pocoData, recordsA);
+ }
+
+ ///
+ /// Bulk-insert records using SqlServer BulkCopy method.
+ ///
+ /// The type of the records.
+ /// The database.
+ /// The PocoData object corresponding to the record's type.
+ /// The records.
+ /// The number of records that were inserted.
+ private int BulkInsertRecordsSqlServer(IUmbracoDatabase database, PocoData pocoData, IEnumerable records)
+ {
+ // TODO: The main reason this exists is because the NPoco InsertBulk method doesn't return the number of items.
+ // It is worth investigating the performance of this vs NPoco's because we use a custom BulkDataReader
+ // which in theory should be more efficient than NPocos way of building up an in-memory DataTable.
+
+ // create command against the original database.Connection
+ using (DbCommand command = database.CreateCommand(database.Connection, CommandType.Text, string.Empty))
+ {
+ // use typed connection and transaction or SqlBulkCopy
+ SqlConnection tConnection = NPocoDatabaseExtensions.GetTypedConnection(database.Connection);
+ SqlTransaction tTransaction =
+ NPocoDatabaseExtensions.GetTypedTransaction(command.Transaction);
+ var tableName = pocoData.TableInfo.TableName;
+
+ if (database.SqlContext.SqlSyntax is not SqlServerSyntaxProvider syntax)
{
- // use typed connection and transaction or SqlBulkCopy
- var tConnection = NPocoDatabaseExtensions.GetTypedConnection(database.Connection);
- var tTransaction = NPocoDatabaseExtensions.GetTypedTransaction(command.Transaction);
- var tableName = pocoData.TableInfo.TableName;
+ throw new NotSupportedException("SqlSyntax must be SqlServerSyntaxProvider.");
+ }
- var syntax = database.SqlContext.SqlSyntax as SqlServerSyntaxProvider;
- if (syntax == null) throw new NotSupportedException("SqlSyntax must be SqlServerSyntaxProvider.");
+ using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction)
+ {
+ // 0 = no bulk copy timeout. If a timeout occurs it will be an connection/command timeout.
+ BulkCopyTimeout = 0,
+ DestinationTableName = tableName,
- using (var copy = new SqlBulkCopy(tConnection, SqlBulkCopyOptions.Default, tTransaction)
+ // be consistent with NPoco: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L50
+ BatchSize = 4096,
+ })
+ using (var bulkReader = new PocoDataDataReader(records, pocoData, syntax))
+ {
+ // we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared
+ // to the order in which they are declared in the model then this will not work, so instead we will add column mappings by name so that this explicitly uses
+ // the names instead of their ordering.
+ foreach (SqlBulkCopyColumnMapping col in bulkReader.ColumnMappings)
{
- BulkCopyTimeout = 0, // 0 = no bulk copy timeout. If a timeout occurs it will be an connection/command timeout.
- DestinationTableName = tableName,
- // be consistent with NPoco: https://github.com/schotime/NPoco/blob/5117a55fde57547e928246c044fd40bd00b2d7d1/src/NPoco.SqlServer/SqlBulkCopyHelper.cs#L50
- BatchSize = 4096
- })
- using (var bulkReader = new PocoDataDataReader(records, pocoData, syntax))
- {
- //we need to add column mappings here because otherwise columns will be matched by their order and if the order of them are different in the DB compared
- //to the order in which they are declared in the model then this will not work, so instead we will add column mappings by name so that this explicitly uses
- //the names instead of their ordering.
- foreach (var col in bulkReader.ColumnMappings)
- {
- copy.ColumnMappings.Add(col.DestinationColumn, col.DestinationColumn);
- }
-
- copy.WriteToServer(bulkReader);
- return bulkReader.RecordsAffected;
+ copy.ColumnMappings.Add(col.DestinationColumn, col.DestinationColumn);
}
+
+ copy.WriteToServer(bulkReader);
+ return bulkReader.RecordsAffected;
}
}
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseCreator.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseCreator.cs
index 205519d0b1..dd092e820d 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseCreator.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseCreator.cs
@@ -1,61 +1,60 @@
using Microsoft.Data.SqlClient;
using Umbraco.Cms.Infrastructure.Persistence;
-namespace Umbraco.Cms.Persistence.SqlServer.Services
+namespace Umbraco.Cms.Persistence.SqlServer.Services;
+
+public class SqlServerDatabaseCreator : IDatabaseCreator
{
- public class SqlServerDatabaseCreator : IDatabaseCreator
+ public string ProviderName => Constants.ProviderName;
+
+ public void Create(string connectionString)
{
- public string ProviderName => Constants.ProviderName;
+ var builder = new SqlConnectionStringBuilder(connectionString);
- public void Create(string connectionString)
+ // Get connection string without database specific information
+ var masterBuilder = new SqlConnectionStringBuilder(builder.ConnectionString)
{
- var builder = new SqlConnectionStringBuilder(connectionString);
+ AttachDBFilename = string.Empty,
+ InitialCatalog = string.Empty
+ };
+ var masterConnectionString = masterBuilder.ConnectionString;
- // Get connection string without database specific information
- var masterBuilder = new SqlConnectionStringBuilder(builder.ConnectionString)
+ string fileName = builder.AttachDBFilename,
+ database = builder.InitialCatalog;
+
+ // Create database
+ if (!string.IsNullOrEmpty(fileName) && !File.Exists(fileName))
+ {
+ if (string.IsNullOrWhiteSpace(database))
{
- AttachDBFilename = string.Empty,
- InitialCatalog = string.Empty
- };
- var masterConnectionString = masterBuilder.ConnectionString;
-
- string fileName = builder.AttachDBFilename,
- database = builder.InitialCatalog;
-
- // Create database
- if (!string.IsNullOrEmpty(fileName) && !File.Exists(fileName))
- {
- if (string.IsNullOrWhiteSpace(database))
- {
- // Use a temporary database name
- database = "Umbraco-" + Guid.NewGuid();
- }
-
- using var connection = new SqlConnection(masterConnectionString);
- connection.Open();
-
- using var command = new SqlCommand(
- $"CREATE DATABASE [{database}] ON (NAME='{database}', FILENAME='{fileName}');" +
- $"ALTER DATABASE [{database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;" +
- $"EXEC sp_detach_db @dbname='{database}';",
- connection);
- command.ExecuteNonQuery();
-
- connection.Close();
+ // Use a temporary database name
+ database = "Umbraco-" + Guid.NewGuid();
}
- else if (!string.IsNullOrEmpty(database))
- {
- using var connection = new SqlConnection(masterConnectionString);
- connection.Open();
- using var command = new SqlCommand(
- $"IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = '{database}') " +
- $"CREATE DATABASE [{database}];",
- connection);
- command.ExecuteNonQuery();
+ using var connection = new SqlConnection(masterConnectionString);
+ connection.Open();
- connection.Close();
- }
+ using var command = new SqlCommand(
+ $"CREATE DATABASE [{database}] ON (NAME='{database}', FILENAME='{fileName}');" +
+ $"ALTER DATABASE [{database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;" +
+ $"EXEC sp_detach_db @dbname='{database}';",
+ connection);
+ command.ExecuteNonQuery();
+
+ connection.Close();
+ }
+ else if (!string.IsNullOrEmpty(database))
+ {
+ using var connection = new SqlConnection(masterConnectionString);
+ connection.Open();
+
+ using var command = new SqlCommand(
+ $"IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = '{database}') " +
+ $"CREATE DATABASE [{database}];",
+ connection);
+ command.ExecuteNonQuery();
+
+ connection.Close();
}
}
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs
index 8c840f1778..8b36736804 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDatabaseProviderMetadata.cs
@@ -5,13 +5,13 @@ using Umbraco.Cms.Infrastructure.Persistence;
namespace Umbraco.Cms.Persistence.SqlServer.Services;
///
-/// Provider metadata for SQL Server
+/// Provider metadata for SQL Server
///
[DataContract]
public class SqlServerDatabaseProviderMetadata : IDatabaseProviderMetadata
{
///
- public Guid Id => new ("5e1ad149-1951-4b74-90bf-2ac2aada9e73");
+ public Guid Id => new("5e1ad149-1951-4b74-90bf-2ac2aada9e73");
///
public int SortOrder => 2;
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs
index 7c8effb2b3..12a0afea47 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerDistributedLockingMechanism.cs
@@ -13,17 +13,17 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Persistence.SqlServer.Services;
///
-/// SQL Server implementation of .
+/// SQL Server implementation of .
///
public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism
{
+ private readonly IOptionsMonitor _connectionStrings;
+ private readonly IOptionsMonitor _globalSettings;
private readonly ILogger _logger;
private readonly Lazy _scopeAccessor; // Hooray it's a circular dependency.
- private readonly IOptionsMonitor _globalSettings;
- private readonly IOptionsMonitor _connectionStrings;
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
public SqlServerDistributedLockingMechanism(
ILogger logger,
@@ -104,11 +104,9 @@ public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism
public DistributedLockType LockType { get; }
- public void Dispose()
- {
+ public void Dispose() =>
// Mostly no op, cleaned up by completing transaction in scope.
_parent._logger.LogDebug("Dropped {lockType} for id {id}", LockType, LockId);
- }
public override string ToString()
=> $"SqlServerDistributedLock({LockId}, {LockType}";
@@ -124,19 +122,21 @@ public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism
if (!db.InTransaction)
{
- throw new InvalidOperationException("SqlServerDistributedLockingMechanism requires a transaction to function.");
+ throw new InvalidOperationException(
+ "SqlServerDistributedLockingMechanism requires a transaction to function.");
}
if (db.Transaction.IsolationLevel < IsolationLevel.ReadCommitted)
{
- throw new InvalidOperationException("A transaction with minimum ReadCommitted isolation level is required.");
+ throw new InvalidOperationException(
+ "A transaction with minimum ReadCommitted isolation level is required.");
}
const string query = "SELECT value FROM umbracoLock WITH (REPEATABLEREAD) WHERE id=@id";
db.Execute("SET LOCK_TIMEOUT " + _timeout.TotalMilliseconds + ";");
- var i = db.ExecuteScalar(query, new {id = LockId});
+ var i = db.ExecuteScalar(query, new { id = LockId });
if (i == null)
{
@@ -156,19 +156,22 @@ public class SqlServerDistributedLockingMechanism : IDistributedLockingMechanism
if (!db.InTransaction)
{
- throw new InvalidOperationException("SqlServerDistributedLockingMechanism requires a transaction to function.");
+ throw new InvalidOperationException(
+ "SqlServerDistributedLockingMechanism requires a transaction to function.");
}
if (db.Transaction.IsolationLevel < IsolationLevel.ReadCommitted)
{
- throw new InvalidOperationException("A transaction with minimum ReadCommitted isolation level is required.");
+ throw new InvalidOperationException(
+ "A transaction with minimum ReadCommitted isolation level is required.");
}
- const string query = @"UPDATE umbracoLock WITH (REPEATABLEREAD) SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id";
+ const string query =
+ @"UPDATE umbracoLock WITH (REPEATABLEREAD) SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id";
db.Execute("SET LOCK_TIMEOUT " + _timeout.TotalMilliseconds + ";");
- var i = db.Execute(query, new {id = LockId});
+ var i = db.Execute(query, new { id = LockId });
if (i == 0)
{
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerSyntaxProvider.cs b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerSyntaxProvider.cs
index a4fc33d98c..64ed9e3566 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerSyntaxProvider.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/Services/SqlServerSyntaxProvider.cs
@@ -1,4 +1,5 @@
using System.Data;
+using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Logging;
@@ -12,146 +13,133 @@ using Umbraco.Cms.Persistence.SqlServer.Dtos;
using Umbraco.Extensions;
using ColumnInfo = Umbraco.Cms.Infrastructure.Persistence.SqlSyntax.ColumnInfo;
-namespace Umbraco.Cms.Persistence.SqlServer.Services
+namespace Umbraco.Cms.Persistence.SqlServer.Services;
+
+///
+/// Represents an SqlSyntaxProvider for Sql Server.
+///
+public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase
{
- ///
- /// Represents an SqlSyntaxProvider for Sql Server.
- ///
- public class SqlServerSyntaxProvider : MicrosoftSqlSyntaxProviderBase
+ public enum EngineEdition
{
- private readonly IOptions _globalSettings;
- private readonly ILogger _logger;
+ Unknown = 0,
+ Desktop = 1,
+ Standard = 2,
+ Enterprise = 3, // Also developer edition
+ Express = 4,
+ Azure = 5,
+ }
- public SqlServerSyntaxProvider(IOptions globalSettings)
- : this(globalSettings, StaticApplicationLogging.CreateLogger())
+ public enum VersionName
+ {
+ Invalid = -1,
+ Unknown = 0,
+ V7 = 1,
+ V2000 = 2,
+ V2005 = 3,
+ V2008 = 4,
+ V2012 = 5,
+ V2014 = 6,
+ V2016 = 7,
+ V2017 = 8,
+ V2019 = 9,
+ Other = 99,
+ }
+
+ private readonly IOptions _globalSettings;
+ private readonly ILogger _logger;
+
+ public SqlServerSyntaxProvider(IOptions globalSettings)
+ : this(globalSettings, StaticApplicationLogging.CreateLogger())
+ {
+ }
+
+ public SqlServerSyntaxProvider(IOptions globalSettings, ILogger logger)
+ {
+ _globalSettings = globalSettings;
+ _logger = logger;
+ }
+
+ public override string ProviderName => Constants.ProviderName;
+
+ public ServerVersionInfo? ServerVersion { get; private set; }
+
+ public override string DbProvider => ServerVersion?.IsAzure ?? false ? "SqlAzure" : "SqlServer";
+
+ public override IsolationLevel DefaultIsolationLevel => IsolationLevel.ReadCommitted;
+
+ public override string DeleteDefaultConstraint => "ALTER TABLE {0} DROP CONSTRAINT {2}";
+
+ public override string DropIndex => "DROP INDEX {0} ON {1}";
+
+ public override string RenameColumn => "sp_rename '{0}.{1}', '{2}', 'COLUMN'";
+
+ public override string CreateIndex => "CREATE {0}{1}INDEX {2} ON {3} ({4}){5}";
+
+ public override DatabaseType GetUpdatedDatabaseType(DatabaseType current, string? connectionString)
+ {
+ var setting = _globalSettings.Value.DatabaseFactoryServerVersion;
+ var fromSettings = false;
+
+ if (setting.IsNullOrWhiteSpace() || !setting.StartsWith("SqlServer.")
+ || !Enum.TryParse(setting.Substring("SqlServer.".Length), out VersionName versionName, true))
{
+ versionName = GetSetVersion(connectionString, ProviderName, _logger).ProductVersionName;
}
- public SqlServerSyntaxProvider(IOptions globalSettings, ILogger logger)
+ _logger.LogDebug("SqlServer {SqlServerVersion}, DatabaseType is {DatabaseType} ({Source}).", versionName, DatabaseType.SqlServer2012, fromSettings ? "settings" : "detected");
+
+ return DatabaseType.SqlServer2012;
+ }
+
+ private static VersionName MapProductVersion(string productVersion)
+ {
+ var firstPart = string.IsNullOrWhiteSpace(productVersion)
+ ? "??"
+ : productVersion.Split(Core.Constants.CharArrays.Period)[0];
+ switch (firstPart)
{
- _globalSettings = globalSettings;
- _logger = logger;
+ case "??":
+ return VersionName.Invalid;
+ case "15":
+ return VersionName.V2019;
+ case "14":
+ return VersionName.V2017;
+ case "13":
+ return VersionName.V2016;
+ case "12":
+ return VersionName.V2014;
+ case "11":
+ return VersionName.V2012;
+ case "10":
+ return VersionName.V2008;
+ case "9":
+ return VersionName.V2005;
+ case "8":
+ return VersionName.V2000;
+ case "7":
+ return VersionName.V7;
+ default:
+ return VersionName.Other;
+ }
+ }
+
+ internal ServerVersionInfo GetSetVersion(string? connectionString, string? providerName, ILogger logger)
+ {
+ // var factory = DbProviderFactories.GetFactory(providerName);
+ SqlClientFactory? factory = SqlClientFactory.Instance;
+ DbConnection? connection = factory.CreateConnection();
+
+ if (connection == null)
+ {
+ throw new InvalidOperationException($"Could not create a connection for provider \"{providerName}\".");
}
- public override string ProviderName => Constants.ProviderName;
+ // Edition: "Express Edition", "Windows Azure SQL Database..."
+ // EngineEdition: 1/Desktop 2/Standard 3/Enterprise 4/Express 5/Azure
+ // ProductLevel: RTM, SPx, CTP...
- public ServerVersionInfo? ServerVersion { get; private set; }
-
- public enum VersionName
- {
- Invalid = -1,
- Unknown = 0,
- V7 = 1,
- V2000 = 2,
- V2005 = 3,
- V2008 = 4,
- V2012 = 5,
- V2014 = 6,
- V2016 = 7,
- V2017 = 8,
- V2019 = 9,
- Other = 99
- }
-
- public enum EngineEdition
- {
- Unknown = 0,
- Desktop = 1,
- Standard = 2,
- Enterprise = 3,// Also developer edition
- Express = 4,
- Azure = 5
- }
-
- public override DatabaseType GetUpdatedDatabaseType(DatabaseType current, string? connectionString)
- {
- var setting = _globalSettings.Value.DatabaseFactoryServerVersion;
- var fromSettings = false;
-
- if (setting.IsNullOrWhiteSpace() || !setting.StartsWith("SqlServer.")
- || !Enum.TryParse(setting.Substring("SqlServer.".Length), out var versionName, true))
- {
- versionName = GetSetVersion(connectionString, ProviderName, _logger).ProductVersionName;
- }
-
- _logger.LogDebug("SqlServer {SqlServerVersion}, DatabaseType is {DatabaseType} ({Source}).", versionName, DatabaseType.SqlServer2012, fromSettings ? "settings" : "detected");
-
- return DatabaseType.SqlServer2012;
- }
-
- public class ServerVersionInfo
- {
- public ServerVersionInfo()
- {
- ProductVersionName = VersionName.Unknown;
- EngineEdition = EngineEdition.Unknown;
- }
-
- public ServerVersionInfo(string edition, string instanceName, string productVersion, EngineEdition engineEdition, string machineName, string productLevel)
- {
- Edition = edition;
- InstanceName = instanceName;
- ProductVersion = productVersion;
- ProductVersionName = MapProductVersion(ProductVersion);
- EngineEdition = engineEdition;
- MachineName = machineName;
- ProductLevel = productLevel;
- }
-
- public string? Edition { get; }
- public string? InstanceName { get; }
- public string? ProductVersion { get; }
- public VersionName ProductVersionName { get; }
- public EngineEdition EngineEdition { get; }
- public bool IsAzure => EngineEdition == EngineEdition.Azure;
- public string? MachineName { get; }
- public string? ProductLevel { get; }
- }
-
- private static VersionName MapProductVersion(string productVersion)
- {
- var firstPart = string.IsNullOrWhiteSpace(productVersion) ? "??" : productVersion.Split(Cms.Core.Constants.CharArrays.Period)[0];
- switch (firstPart)
- {
- case "??":
- return VersionName.Invalid;
- case "15":
- return VersionName.V2019;
- case "14":
- return VersionName.V2017;
- case "13":
- return VersionName.V2016;
- case "12":
- return VersionName.V2014;
- case "11":
- return VersionName.V2012;
- case "10":
- return VersionName.V2008;
- case "9":
- return VersionName.V2005;
- case "8":
- return VersionName.V2000;
- case "7":
- return VersionName.V7;
- default:
- return VersionName.Other;
- }
- }
-
- internal ServerVersionInfo GetSetVersion(string? connectionString, string? providerName, ILogger logger)
- {
- //var factory = DbProviderFactories.GetFactory(providerName);
- var factory = SqlClientFactory.Instance;
- var connection = factory.CreateConnection();
-
- if (connection == null)
- throw new InvalidOperationException($"Could not create a connection for provider \"{providerName}\".");
-
- // Edition: "Express Edition", "Windows Azure SQL Database..."
- // EngineEdition: 1/Desktop 2/Standard 3/Enterprise 4/Express 5/Azure
- // ProductLevel: RTM, SPx, CTP...
-
- const string sql = @"select
+ const string sql = @"select
SERVERPROPERTY('Edition') Edition,
SERVERPROPERTY('EditionID') EditionId,
SERVERPROPERTY('InstanceName') InstanceName,
@@ -163,99 +151,102 @@ namespace Umbraco.Cms.Persistence.SqlServer.Services
SERVERPROPERTY('ResourceLastUpdateDateTime') ResourceLastUpdateDateTime,
SERVERPROPERTY('ProductLevel') ProductLevel;";
- string GetString(IDataReader reader, int ordinal, string defaultValue)
- => reader.IsDBNull(ordinal) ? defaultValue : reader.GetString(ordinal);
+ string GetString(IDataReader reader, int ordinal, string defaultValue)
+ {
+ return reader.IsDBNull(ordinal) ? defaultValue : reader.GetString(ordinal);
+ }
- int GetInt32(IDataReader reader, int ordinal, int defaultValue)
- => reader.IsDBNull(ordinal) ? defaultValue : reader.GetInt32(ordinal);
+ int GetInt32(IDataReader reader, int ordinal, int defaultValue)
+ {
+ return reader.IsDBNull(ordinal) ? defaultValue : reader.GetInt32(ordinal);
+ }
- connection.ConnectionString = connectionString;
- ServerVersionInfo version;
- using (connection)
+ connection.ConnectionString = connectionString;
+ ServerVersionInfo version;
+ using (connection)
+ {
+ try
{
- try
+ connection.Open();
+ DbCommand command = connection.CreateCommand();
+ command.CommandText = sql;
+ using (DbDataReader reader = command.ExecuteReader())
{
- connection.Open();
- var command = connection.CreateCommand();
- command.CommandText = sql;
- using (var reader = command.ExecuteReader())
- {
- reader.Read();
- // InstanceName can be NULL for the default instance
- version = new ServerVersionInfo(
- GetString(reader, 0, "Unknown"),
- GetString(reader, 2, "(default)"),
- GetString(reader, 3, string.Empty),
- (EngineEdition) GetInt32(reader, 5, 0),
- GetString(reader, 7, "DEFAULT"),
- GetString(reader, 9, "Unknown"));
- }
- connection.Close();
- }
- catch (Exception e)
- {
- logger.LogError(e, "Failed to detected SqlServer version.");
- version = new ServerVersionInfo(); // all unknown
+ reader.Read();
+ // InstanceName can be NULL for the default instance
+ version = new ServerVersionInfo(
+ GetString(reader, 0, "Unknown"),
+ GetString(reader, 2, "(default)"),
+ GetString(reader, 3, string.Empty),
+ (EngineEdition)GetInt32(reader, 5, 0),
+ GetString(reader, 7, "DEFAULT"),
+ GetString(reader, 9, "Unknown"));
}
+
+ connection.Close();
+ }
+ catch (Exception e)
+ {
+ logger.LogError(e, "Failed to detected SqlServer version.");
+ version = new ServerVersionInfo(); // all unknown
}
-
- return ServerVersion = version;
}
- ///
- /// SQL Server stores default values assigned to columns as constraints, it also stores them with named values, this is the only
- /// server type that does this, therefore this method doesn't exist on any other syntax provider
- ///
- ///
- public IEnumerable> GetDefaultConstraintsPerColumn(IDatabase db)
- {
- var items = db.Fetch("SELECT TableName = t.Name, ColumnName = c.Name, dc.Name, dc.[Definition] FROM sys.tables t INNER JOIN sys.default_constraints dc ON t.object_id = dc.parent_object_id INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id AND c.column_id = dc.parent_column_id INNER JOIN sys.schemas as s on t.[schema_id] = s.[schema_id] WHERE s.name = (SELECT SCHEMA_NAME())");
- return items.Select(x => new Tuple(x.TableName, x.ColumnName, x.Name, x.Definition));
- }
+ return ServerVersion = version;
+ }
- public override string DbProvider => ServerVersion?.IsAzure ?? false ? "SqlAzure" : "SqlServer";
+ ///
+ /// SQL Server stores default values assigned to columns as constraints, it also stores them with named values, this is
+ /// the only
+ /// server type that does this, therefore this method doesn't exist on any other syntax provider
+ ///
+ ///
+ public IEnumerable> GetDefaultConstraintsPerColumn(IDatabase db)
+ {
+ List? items = db.Fetch(
+ "SELECT TableName = t.Name, ColumnName = c.Name, dc.Name, dc.[Definition] FROM sys.tables t INNER JOIN sys.default_constraints dc ON t.object_id = dc.parent_object_id INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id AND c.column_id = dc.parent_column_id INNER JOIN sys.schemas as s on t.[schema_id] = s.[schema_id] WHERE s.name = (SELECT SCHEMA_NAME())");
+ return items.Select(x =>
+ new Tuple(x.TableName, x.ColumnName, x.Name, x.Definition));
+ }
- public override IEnumerable GetTablesInSchema(IDatabase db)
- {
- return db.Fetch("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
- }
+ public override IEnumerable GetTablesInSchema(IDatabase db) => db.Fetch(
+ "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
- public override IsolationLevel DefaultIsolationLevel => IsolationLevel.ReadCommitted;
+ public override IEnumerable GetColumnsInSchema(IDatabase db)
+ {
+ List? items = db.Fetch(
+ "SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
+ return
+ items.Select(
+ item =>
+ new ColumnInfo(item.TableName, item.ColumnName, item.OrdinalPosition, item.ColumnDefault, item.IsNullable, item.DataType)).ToList();
+ }
- public override IEnumerable GetColumnsInSchema(IDatabase db)
- {
- var items = db.Fetch("SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION, COLUMN_DEFAULT, IS_NULLABLE, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
- return
- items.Select(
- item =>
- new ColumnInfo(item.TableName, item.ColumnName, item.OrdinalPosition, item.ColumnDefault,
- item.IsNullable, item.DataType)).ToList();
- }
+ ///
+ public override IEnumerable> GetConstraintsPerTable(IDatabase db)
+ {
+ List items =
+ db.Fetch(
+ "SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
+ return items.Select(item => new Tuple(item.TableName, item.ConstraintName)).ToList();
+ }
- ///
- public override IEnumerable> GetConstraintsPerTable(IDatabase db)
- {
- var items =
- db.Fetch(
- "SELECT TABLE_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_TABLE_USAGE WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
- return items.Select(item => new Tuple(item.TableName, item.ConstraintName)).ToList();
- }
+ ///
+ public override IEnumerable> GetConstraintsPerColumn(IDatabase db)
+ {
+ List? items =
+ db.Fetch(
+ "SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
+ return items.Select(item =>
+ new Tuple(item.TableName, item.ColumnName, item.ConstraintName)).ToList();
+ }
- ///
- public override IEnumerable> GetConstraintsPerColumn(IDatabase db)
- {
- var items =
- db.Fetch(
- "SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_SCHEMA = (SELECT SCHEMA_NAME())");
- return items.Select(item => new Tuple(item.TableName, item.ColumnName, item.ConstraintName)).ToList();
- }
-
- ///
- public override IEnumerable> GetDefinedIndexes(IDatabase db)
- {
- var items =
- db.Fetch(
- @"select T.name as TABLE_NAME, I.name as INDEX_NAME, AC.Name as COLUMN_NAME,
+ ///
+ public override IEnumerable> GetDefinedIndexes(IDatabase db)
+ {
+ List? items =
+ db.Fetch(
+ @"select T.name as TABLE_NAME, I.name as INDEX_NAME, AC.Name as COLUMN_NAME,
CASE WHEN I.is_unique_constraint = 1 OR I.is_unique = 1 THEN 1 ELSE 0 END AS [UNIQUE]
from sys.tables as T inner join sys.indexes as I on T.[object_id] = I.[object_id]
inner join sys.index_columns as IC on IC.[object_id] = I.[object_id] and IC.[index_id] = I.[index_id]
@@ -263,182 +254,203 @@ from sys.tables as T inner join sys.indexes as I on T.[object_id] = I.[object_id
inner join sys.schemas as S on T.[schema_id] = S.[schema_id]
WHERE S.name = (SELECT SCHEMA_NAME()) AND I.is_primary_key = 0
order by T.name, I.name");
- return items.Select(item => new Tuple(item.TableName, item.IndexName, item.ColumnName,
- item.Unique == 1)).ToList();
+ return items.Select(item => new Tuple(item.TableName, item.IndexName, item.ColumnName, item.Unique == 1)).ToList();
+ }
- }
-
- ///
- public override bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName, [MaybeNullWhen(false)] out string constraintName)
- {
- constraintName = db.Fetch(@"select con.[name] as [constraintName]
+ ///
+ public override bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName, [MaybeNullWhen(false)] out string constraintName)
+ {
+ constraintName = db.Fetch(
+ @"select con.[name] as [constraintName]
from sys.default_constraints con
join sys.columns col on con.object_id=col.default_object_id
join sys.tables tbl on col.object_id=tbl.object_id
-where tbl.[name]=@0 and col.[name]=@1;", tableName, columnName)
- .FirstOrDefault();
- return !constraintName.IsNullOrWhiteSpace();
- }
-
- public override bool DoesTableExist(IDatabase db, string tableName)
- {
- var result =
- db.ExecuteScalar("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName AND TABLE_SCHEMA = (SELECT SCHEMA_NAME())",
- new { TableName = tableName });
-
- return result > 0;
- }
-
- public override string FormatColumnRename(string? tableName, string? oldName, string? newName)
- {
- return string.Format(RenameColumn, tableName, oldName, newName);
- }
-
- public override string FormatTableRename(string? oldName, string? newName)
- {
- return string.Format(RenameTable, oldName, newName);
- }
-
- protected override string FormatIdentity(ColumnDefinition column)
- {
- return column.IsIdentity ? GetIdentityString(column) : string.Empty;
- }
-
- public override Sql SelectTop(Sql sql, int top)
- {
- return new Sql(sql.SqlContext, sql.SQL.Insert(sql.SQL.IndexOf(' '), " TOP " + top), sql.Arguments);
- }
-
- private static string GetIdentityString(ColumnDefinition column)
- {
- return "IDENTITY(1,1)";
- }
-
- protected override string? FormatSystemMethods(SystemMethods systemMethod)
- {
- switch (systemMethod)
- {
- case SystemMethods.NewGuid:
- return "NEWID()";
- case SystemMethods.CurrentDateTime:
- return "GETDATE()";
- //case SystemMethods.NewSequentialId:
- // return "NEWSEQUENTIALID()";
- //case SystemMethods.CurrentUTCDateTime:
- // return "GETUTCDATE()";
- }
-
- return null;
- }
-
- public override string DeleteDefaultConstraint => "ALTER TABLE {0} DROP CONSTRAINT {2}";
-
- public override string DropIndex => "DROP INDEX {0} ON {1}";
-
- public override string RenameColumn => "sp_rename '{0}.{1}', '{2}', 'COLUMN'";
-
- public override string CreateIndex => "CREATE {0}{1}INDEX {2} ON {3} ({4}){5}";
- public override string Format(IndexDefinition index)
- {
- var name = string.IsNullOrEmpty(index.Name)
- ? $"IX_{index.TableName}_{index.ColumnName}"
- : index.Name;
-
- var columns = index.Columns.Any()
- ? string.Join(",", index.Columns.Select(x => GetQuotedColumnName(x.Name)))
- : GetQuotedColumnName(index.ColumnName);
-
- var includeColumns = index.IncludeColumns?.Any() ?? false
- ? $" INCLUDE ({string.Join(",", index.IncludeColumns.Select(x => GetQuotedColumnName(x.Name)))})"
- : string.Empty;
-
- return string.Format(CreateIndex, GetIndexType(index.IndexType), " ", GetQuotedName(name),
- GetQuotedTableName(index.TableName), columns, includeColumns);
- }
-
-
- public override Sql InsertForUpdateHint(Sql sql)
- {
- // go find the first FROM clause, and append the lock hint
- Sql s = sql;
- var updated = false;
-
- while (s != null)
- {
- var sqlText = SqlInspector.GetSqlText(s);
- if (sqlText.StartsWith("FROM ", StringComparison.OrdinalIgnoreCase))
- {
- SqlInspector.SetSqlText(s, sqlText + " WITH (UPDLOCK)");
- updated = true;
- break;
- }
-
- s = SqlInspector.GetSqlRhs(sql);
- }
-
- if (updated)
- SqlInspector.Reset(sql);
-
- return sql;
- }
-
- public override Sql AppendForUpdateHint(Sql sql)
- => sql.Append(" WITH (UPDLOCK) ");
-
- public override Sql.SqlJoinClause LeftJoinWithNestedJoin(
- Sql sql,
- Func,
- Sql> nestedJoin,
- string? alias = null)
- {
- Type type = typeof(TDto);
-
- var tableName = GetQuotedTableName(type.GetTableName());
- var join = tableName;
-
- if (alias != null)
- {
- var quotedAlias = GetQuotedTableName(alias);
- join += " " + quotedAlias;
- }
-
- var nestedSql = new Sql(sql.SqlContext);
- nestedSql = nestedJoin(nestedSql);
-
- Sql.SqlJoinClause sqlJoin = sql.LeftJoin(join);
- sql.Append(nestedSql);
- return sqlJoin;
- }
-
- #region Sql Inspection
-
- private static SqlInspectionUtilities? _sqlInspector;
-
- private static SqlInspectionUtilities SqlInspector => _sqlInspector ?? (_sqlInspector = new SqlInspectionUtilities());
-
- private class SqlInspectionUtilities
- {
- private readonly Func _getSqlText;
- private readonly Action _setSqlText;
- private readonly Func _getSqlRhs;
- private readonly Action _setSqlFinal;
-
- public SqlInspectionUtilities()
- {
- (_getSqlText, _setSqlText) = ReflectionUtilities.EmitFieldGetterAndSetter("_sql");
- _getSqlRhs = ReflectionUtilities.EmitFieldGetter("_rhs");
- _setSqlFinal = ReflectionUtilities.EmitFieldSetter("_sqlFinal");
- }
-
- public string GetSqlText(Sql sql) => _getSqlText(sql);
-
- public void SetSqlText(Sql sql, string sqlText) => _setSqlText(sql, sqlText);
-
- public Sql GetSqlRhs(Sql sql) => _getSqlRhs(sql);
-
- public void Reset(Sql sql) => _setSqlFinal(sql, null);
- }
-
- #endregion
+where tbl.[name]=@0 and col.[name]=@1;",
+ tableName,
+ columnName)
+ .FirstOrDefault();
+ return !constraintName.IsNullOrWhiteSpace();
}
+
+ public override bool DoesTableExist(IDatabase db, string tableName)
+ {
+ var result =
+ db.ExecuteScalar(
+ "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName AND TABLE_SCHEMA = (SELECT SCHEMA_NAME())",
+ new { TableName = tableName });
+
+ return result > 0;
+ }
+
+ public override string FormatColumnRename(string? tableName, string? oldName, string? newName) =>
+ string.Format(RenameColumn, tableName, oldName, newName);
+
+ public override string FormatTableRename(string? oldName, string? newName) =>
+ string.Format(RenameTable, oldName, newName);
+
+ protected override string FormatIdentity(ColumnDefinition column) =>
+ column.IsIdentity ? GetIdentityString(column) : string.Empty;
+
+ public override Sql SelectTop(Sql sql, int top) => new Sql(sql.SqlContext, sql.SQL.Insert(sql.SQL.IndexOf(' '), " TOP " + top), sql.Arguments);
+
+ private static string GetIdentityString(ColumnDefinition column) => "IDENTITY(1,1)";
+
+ protected override string? FormatSystemMethods(SystemMethods systemMethod)
+ {
+ switch (systemMethod)
+ {
+ case SystemMethods.NewGuid:
+ return "NEWID()";
+ case SystemMethods.CurrentDateTime:
+ return "GETDATE()";
+
+ // case SystemMethods.NewSequentialId:
+ // return "NEWSEQUENTIALID()";
+ // case SystemMethods.CurrentUTCDateTime:
+ // return "GETUTCDATE()";
+ }
+
+ return null;
+ }
+
+ public override string Format(IndexDefinition index)
+ {
+ var name = string.IsNullOrEmpty(index.Name)
+ ? $"IX_{index.TableName}_{index.ColumnName}"
+ : index.Name;
+
+ var columns = index.Columns.Any()
+ ? string.Join(",", index.Columns.Select(x => GetQuotedColumnName(x.Name)))
+ : GetQuotedColumnName(index.ColumnName);
+
+ var includeColumns = index.IncludeColumns?.Any() ?? false
+ ? $" INCLUDE ({string.Join(",", index.IncludeColumns.Select(x => GetQuotedColumnName(x.Name)))})"
+ : string.Empty;
+
+ return string.Format(CreateIndex, GetIndexType(index.IndexType), " ", GetQuotedName(name), GetQuotedTableName(index.TableName), columns, includeColumns);
+ }
+
+
+ public override Sql InsertForUpdateHint(Sql sql)
+ {
+ // go find the first FROM clause, and append the lock hint
+ Sql s = sql;
+ var updated = false;
+
+ while (s != null)
+ {
+ var sqlText = SqlInspector.GetSqlText(s);
+ if (sqlText.StartsWith("FROM ", StringComparison.OrdinalIgnoreCase))
+ {
+ SqlInspector.SetSqlText(s, sqlText + " WITH (UPDLOCK)");
+ updated = true;
+ break;
+ }
+
+ s = SqlInspector.GetSqlRhs(sql);
+ }
+
+ if (updated)
+ {
+ SqlInspector.Reset(sql);
+ }
+
+ return sql;
+ }
+
+ public override Sql AppendForUpdateHint(Sql sql)
+ => sql.Append(" WITH (UPDLOCK) ");
+
+ public override Sql.SqlJoinClause LeftJoinWithNestedJoin(
+ Sql sql,
+ Func,
+ Sql> nestedJoin,
+ string? alias = null)
+ {
+ Type type = typeof(TDto);
+
+ var tableName = GetQuotedTableName(type.GetTableName());
+ var join = tableName;
+
+ if (alias != null)
+ {
+ var quotedAlias = GetQuotedTableName(alias);
+ join += " " + quotedAlias;
+ }
+
+ var nestedSql = new Sql(sql.SqlContext);
+ nestedSql = nestedJoin(nestedSql);
+
+ Sql.SqlJoinClause sqlJoin = sql.LeftJoin(join);
+ sql.Append(nestedSql);
+ return sqlJoin;
+ }
+
+ public class ServerVersionInfo
+ {
+ public ServerVersionInfo()
+ {
+ ProductVersionName = VersionName.Unknown;
+ EngineEdition = EngineEdition.Unknown;
+ }
+
+ public ServerVersionInfo(string edition, string instanceName, string productVersion, EngineEdition engineEdition, string machineName, string productLevel)
+ {
+ Edition = edition;
+ InstanceName = instanceName;
+ ProductVersion = productVersion;
+ ProductVersionName = MapProductVersion(ProductVersion);
+ EngineEdition = engineEdition;
+ MachineName = machineName;
+ ProductLevel = productLevel;
+ }
+
+ public string? Edition { get; }
+
+ public string? InstanceName { get; }
+
+ public string? ProductVersion { get; }
+
+ public VersionName ProductVersionName { get; }
+
+ public EngineEdition EngineEdition { get; }
+
+ public bool IsAzure => EngineEdition == EngineEdition.Azure;
+
+ public string? MachineName { get; }
+
+ public string? ProductLevel { get; }
+ }
+
+ #region Sql Inspection
+
+ private static SqlInspectionUtilities? _sqlInspector;
+
+ private static SqlInspectionUtilities SqlInspector =>
+_sqlInspector ??= new SqlInspectionUtilities();
+
+ private class SqlInspectionUtilities
+ {
+ private readonly Func _getSqlRhs;
+ private readonly Func _getSqlText;
+ private readonly Action _setSqlFinal;
+ private readonly Action _setSqlText;
+
+ public SqlInspectionUtilities()
+ {
+ (_getSqlText, _setSqlText) = ReflectionUtilities.EmitFieldGetterAndSetter("_sql");
+ _getSqlRhs = ReflectionUtilities.EmitFieldGetter("_rhs");
+ _setSqlFinal = ReflectionUtilities.EmitFieldSetter("_sqlFinal");
+ }
+
+ public string GetSqlText(Sql sql) => _getSqlText(sql);
+
+ public void SetSqlText(Sql sql, string sqlText) => _setSqlText(sql, sqlText);
+
+ public Sql GetSqlRhs(Sql sql) => _getSqlRhs(sql);
+
+ public void Reset(Sql sql) => _setSqlFinal(sql, null);
+ }
+
+ #endregion
}
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/SqlServerComposer.cs b/src/Umbraco.Cms.Persistence.SqlServer/SqlServerComposer.cs
index 60d64c09df..e81a65e74f 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/SqlServerComposer.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/SqlServerComposer.cs
@@ -4,7 +4,7 @@ using Umbraco.Cms.Core.DependencyInjection;
namespace Umbraco.Cms.Persistence.SqlServer;
///
-/// Automatically adds SQL Server support to Umbraco when this project is referenced.
+/// Automatically adds SQL Server support to Umbraco when this project is referenced.
///
public class SqlServerComposer : IComposer
{
diff --git a/src/Umbraco.Cms.Persistence.SqlServer/UmbracoBuilderExtensions.cs b/src/Umbraco.Cms.Persistence.SqlServer/UmbracoBuilderExtensions.cs
index 4b9fb8d11a..a47e92bf2e 100644
--- a/src/Umbraco.Cms.Persistence.SqlServer/UmbracoBuilderExtensions.cs
+++ b/src/Umbraco.Cms.Persistence.SqlServer/UmbracoBuilderExtensions.cs
@@ -13,27 +13,34 @@ using Umbraco.Cms.Persistence.SqlServer.Services;
namespace Umbraco.Cms.Persistence.SqlServer;
///
-/// SQLite support extensions for IUmbracoBuilder.
+/// SQLite support extensions for IUmbracoBuilder.
///
public static class UmbracoBuilderExtensions
{
///
- /// Add required services for SQL Server support.
+ /// Add required services for SQL Server support.
///
public static IUmbracoBuilder AddUmbracoSqlServerSupport(this IUmbracoBuilder builder)
{
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
- builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
+ builder.Services.TryAddEnumerable(ServiceDescriptor
+ .Singleton());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
- builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
- builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
- builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
+ builder.Services.TryAddEnumerable(ServiceDescriptor
+ .Singleton());
+ builder.Services.TryAddEnumerable(ServiceDescriptor
+ .Singleton());
+ builder.Services.TryAddEnumerable(ServiceDescriptor
+ .Singleton());
- builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
+ builder.Services.TryAddEnumerable(ServiceDescriptor
+ .Singleton());
- builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
- builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton());
+ builder.Services.TryAddEnumerable(ServiceDescriptor
+ .Singleton());
+ builder.Services.TryAddEnumerable(ServiceDescriptor
+ .Singleton());
DbProviderFactories.UnregisterFactory(Constants.ProviderName);
DbProviderFactories.RegisterFactory(Constants.ProviderName, SqlClientFactory.Instance);
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Constants.cs b/src/Umbraco.Cms.Persistence.Sqlite/Constants.cs
index 76e408423c..63f0d8f9fe 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Constants.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Constants.cs
@@ -1,12 +1,12 @@
namespace Umbraco.Cms.Persistence.Sqlite;
///
-/// Constants related to SQLite.
+/// Constants related to SQLite.
///
public static class Constants
{
///
- /// SQLite provider name.
+ /// SQLite provider name.
///
public const string ProviderName = "Microsoft.Data.SQLite";
}
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Interceptors/SqliteAddMiniProfilerInterceptor.cs b/src/Umbraco.Cms.Persistence.Sqlite/Interceptors/SqliteAddMiniProfilerInterceptor.cs
index eb76319040..9d7f3b29ad 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Interceptors/SqliteAddMiniProfilerInterceptor.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Interceptors/SqliteAddMiniProfilerInterceptor.cs
@@ -1,11 +1,12 @@
using System.Data.Common;
using NPoco;
using StackExchange.Profiling;
+using StackExchange.Profiling.Data;
namespace Umbraco.Cms.Persistence.Sqlite.Interceptors;
public class SqliteAddMiniProfilerInterceptor : SqliteConnectionInterceptor
{
public override DbConnection OnConnectionOpened(IDatabase database, DbConnection conn)
- => new StackExchange.Profiling.Data.ProfiledDbConnection(conn, MiniProfiler.Current);
+ => new ProfiledDbConnection(conn, MiniProfiler.Current);
}
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Interceptors/SqliteAddPreferDeferredInterceptor.cs b/src/Umbraco.Cms.Persistence.Sqlite/Interceptors/SqliteAddPreferDeferredInterceptor.cs
index ef22e9c0b6..5c195291b0 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Interceptors/SqliteAddPreferDeferredInterceptor.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Interceptors/SqliteAddPreferDeferredInterceptor.cs
@@ -8,5 +8,6 @@ namespace Umbraco.Cms.Persistence.Sqlite.Interceptors;
public class SqliteAddPreferDeferredInterceptor : SqliteConnectionInterceptor
{
public override DbConnection OnConnectionOpened(IDatabase database, DbConnection conn)
- => new SqlitePreferDeferredTransactionsConnection(conn as SqliteConnection ?? throw new InvalidOperationException());
+ => new SqlitePreferDeferredTransactionsConnection(conn as SqliteConnection ??
+ throw new InvalidOperationException());
}
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Mappers/SqliteGuidScalarMapper.cs b/src/Umbraco.Cms.Persistence.Sqlite/Mappers/SqliteGuidScalarMapper.cs
index bd9bb1924d..eac4152df4 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Mappers/SqliteGuidScalarMapper.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Mappers/SqliteGuidScalarMapper.cs
@@ -14,7 +14,7 @@ public class SqliteNullableGuidScalarMapper : ScalarMapper
{
if (value is null || value == DBNull.Value)
{
- return default(Guid?);
+ return default;
}
return Guid.TryParse($"{value}", out Guid result)
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Mappers/SqlitePocoGuidMapper.cs b/src/Umbraco.Cms.Persistence.Sqlite/Mappers/SqlitePocoGuidMapper.cs
index f7b2836f1a..930478e453 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Mappers/SqlitePocoGuidMapper.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Mappers/SqlitePocoGuidMapper.cs
@@ -8,7 +8,7 @@ public class SqlitePocoGuidMapper : DefaultMapper
{
if (destType == typeof(Guid))
{
- return (value) =>
+ return value =>
{
var result = Guid.Parse($"{value}");
return result;
@@ -17,7 +17,7 @@ public class SqlitePocoGuidMapper : DefaultMapper
if (destType == typeof(Guid?))
{
- return (value) =>
+ return value =>
{
if (Guid.TryParse($"{value}", out Guid result))
{
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteBulkSqlInsertProvider.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteBulkSqlInsertProvider.cs
index 895ee21ef6..ff0a64a74b 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteBulkSqlInsertProvider.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteBulkSqlInsertProvider.cs
@@ -4,7 +4,7 @@ using Umbraco.Cms.Infrastructure.Persistence;
namespace Umbraco.Cms.Persistence.Sqlite.Services;
///
-/// Implements for SQLite.
+/// Implements for SQLite.
///
public class SqliteBulkSqlInsertProvider : IBulkSqlInsertProvider
{
@@ -12,17 +12,23 @@ public class SqliteBulkSqlInsertProvider : IBulkSqlInsertProvider
public int BulkInsertRecords(IUmbracoDatabase database, IEnumerable records)
{
- var recordsA = records.ToArray();
- if (recordsA.Length == 0) return 0;
+ T[] recordsA = records.ToArray();
+ if (recordsA.Length == 0)
+ {
+ return 0;
+ }
- var pocoData = database.PocoDataFactory.ForType(typeof(T));
- if (pocoData == null) throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
+ PocoData? pocoData = database.PocoDataFactory.ForType(typeof(T));
+ if (pocoData == null)
+ {
+ throw new InvalidOperationException("Could not find PocoData for " + typeof(T));
+ }
return BulkInsertRecordsSqlite(database, pocoData, recordsA);
}
///
- /// Bulk-insert records using SqlServer BulkCopy method.
+ /// Bulk-insert records using SqlServer BulkCopy method.
///
/// The type of the records.
/// The database.
@@ -39,7 +45,7 @@ public class SqliteBulkSqlInsertProvider : IBulkSqlInsertProvider
database.BeginTransaction();
}
- foreach (var record in records)
+ foreach (T record in records)
{
database.Insert(record);
count++;
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseCreator.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseCreator.cs
index 84c8eea1db..54d6063ad7 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseCreator.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseCreator.cs
@@ -1,4 +1,3 @@
-using System.Diagnostics;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Infrastructure.Persistence;
@@ -6,38 +5,35 @@ using Umbraco.Cms.Infrastructure.Persistence;
namespace Umbraco.Cms.Persistence.Sqlite.Services;
///
-/// Implements for SQLite.
+/// Implements for SQLite.
///
public class SqliteDatabaseCreator : IDatabaseCreator
{
private readonly ILogger _logger;
+ public SqliteDatabaseCreator(ILogger logger) => _logger = logger;
+
///
public string ProviderName => Constants.ProviderName;
- public SqliteDatabaseCreator(ILogger logger)
- {
- _logger = logger;
- }
-
///
- /// Creates a SQLite database file.
+ /// Creates a SQLite database file.
///
///
- ///
- /// With journal_mode = wal we have snapshot isolation.
- ///
- ///
- /// Concurrent read/write can take occur, committing a write transaction will have no impact
- /// on open read transactions as they see only committed data from the point in time that they began reading.
- ///
- ///
- /// A write transaction still requires exclusive access to database files so concurrent writes are not possible.
- ///
- ///
- /// Read more Isolation in SQLite
- /// Read more Write-Ahead Logging
- ///
+ ///
+ /// With journal_mode = wal we have snapshot isolation.
+ ///
+ ///
+ /// Concurrent read/write can take occur, committing a write transaction will have no impact
+ /// on open read transactions as they see only committed data from the point in time that they began reading.
+ ///
+ ///
+ /// A write transaction still requires exclusive access to database files so concurrent writes are not possible.
+ ///
+ ///
+ /// Read more Isolation in SQLite
+ /// Read more Write-Ahead Logging
+ ///
///
public void Create(string connectionString)
{
@@ -88,7 +84,7 @@ public class SqliteDatabaseCreator : IDatabaseCreator
// Copy our blank(ish) wal mode sqlite database to its final location.
try
{
- File.Copy(tempFile, original.DataSource, overwrite: true);
+ File.Copy(tempFile, original.DataSource, true);
}
catch (Exception ex)
{
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs
index 0b684551c7..54a7a5cb1d 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDatabaseProviderMetadata.cs
@@ -10,7 +10,7 @@ namespace Umbraco.Cms.Persistence.Sqlite.Services;
public class SqliteDatabaseProviderMetadata : IDatabaseProviderMetadata
{
///
- public Guid Id => new ("530386a2-b219-4d5f-b68c-b965e14c9ac9");
+ public Guid Id => new("530386a2-b219-4d5f-b68c-b965e14c9ac9");
///
public int SortOrder => -1;
@@ -47,12 +47,12 @@ public class SqliteDatabaseProviderMetadata : IDatabaseProviderMetadata
///
///
- ///
- /// Required to ensure database creator is used regardless of configured InstallMissingDatabase value.
- ///
- ///
- /// Ensures database setup with journal_mode = wal;
- ///
+ ///
+ /// Required to ensure database creator is used regardless of configured InstallMissingDatabase value.
+ ///
+ ///
+ /// Ensures database setup with journal_mode = wal;
+ ///
///
public bool ForceCreateDatabase => true;
@@ -64,7 +64,7 @@ public class SqliteDatabaseProviderMetadata : IDatabaseProviderMetadata
DataSource = $"{ConnectionStrings.DataDirectoryPlaceholder}/{databaseModel.DatabaseName}.sqlite.db",
ForeignKeys = true,
Pooling = true,
- Cache = SqliteCacheMode.Shared,
+ Cache = SqliteCacheMode.Shared
};
return builder.ConnectionString;
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs
index 4a47d41846..c704bb8272 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteDistributedLockingMechanism.cs
@@ -4,7 +4,6 @@ using Microsoft.Data.SqlClient;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
-using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DistributedLocking;
using Umbraco.Cms.Core.DistributedLocking.Exceptions;
@@ -17,10 +16,10 @@ namespace Umbraco.Cms.Persistence.Sqlite.Services;
public class SqliteDistributedLockingMechanism : IDistributedLockingMechanism
{
- private readonly ILogger _logger;
- private readonly Lazy _scopeAccessor;
private readonly IOptionsMonitor _connectionStrings;
private readonly IOptionsMonitor _globalSettings;
+ private readonly ILogger _logger;
+ private readonly Lazy _scopeAccessor;
public SqliteDistributedLockingMechanism(
ILogger logger,
@@ -101,11 +100,9 @@ public class SqliteDistributedLockingMechanism : IDistributedLockingMechanism
public DistributedLockType LockType { get; }
- public void Dispose()
- {
+ public void Dispose() =>
// Mostly no op, cleaned up by completing transaction in scope.
_parent._logger.LogDebug("Dropped {lockType} for id {id}", LockType, LockId);
- }
public override string ToString()
=> $"SqliteDistributedLock({LockId})";
@@ -123,7 +120,8 @@ public class SqliteDistributedLockingMechanism : IDistributedLockingMechanism
if (!db.InTransaction)
{
- throw new InvalidOperationException("SqliteDistributedLockingMechanism requires a transaction to function.");
+ throw new InvalidOperationException(
+ "SqliteDistributedLockingMechanism requires a transaction to function.");
}
}
@@ -140,7 +138,8 @@ public class SqliteDistributedLockingMechanism : IDistributedLockingMechanism
if (!db.InTransaction)
{
- throw new InvalidOperationException("SqliteDistributedLockingMechanism requires a transaction to function.");
+ throw new InvalidOperationException(
+ "SqliteDistributedLockingMechanism requires a transaction to function.");
}
var query = @$"UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id = {LockId}";
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteExceptionExtensions.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteExceptionExtensions.cs
index 4076718266..acc8afb508 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteExceptionExtensions.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteExceptionExtensions.cs
@@ -1,4 +1,5 @@
using Microsoft.Data.Sqlite;
+using SQLitePCL;
namespace Umbraco.Cms.Persistence.Sqlite.Services;
@@ -6,7 +7,7 @@ public static class SqliteExceptionExtensions
{
public static bool IsBusyOrLocked(this SqliteException ex) =>
ex.SqliteErrorCode
- is SQLitePCL.raw.SQLITE_BUSY
- or SQLitePCL.raw.SQLITE_LOCKED
- or SQLitePCL.raw.SQLITE_LOCKED_SHAREDCACHE;
+ is raw.SQLITE_BUSY
+ or raw.SQLITE_LOCKED
+ or raw.SQLITE_LOCKED_SHAREDCACHE;
}
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqlitePreferDeferredTransactionsConnection.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqlitePreferDeferredTransactionsConnection.cs
index 4e126056d6..7c5a9f56f8 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqlitePreferDeferredTransactionsConnection.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqlitePreferDeferredTransactionsConnection.cs
@@ -9,22 +9,7 @@ public class SqlitePreferDeferredTransactionsConnection : DbConnection
{
private readonly SqliteConnection _inner;
- public SqlitePreferDeferredTransactionsConnection(SqliteConnection inner)
- {
- _inner = inner;
- }
-
- protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
- => _inner.BeginTransaction(isolationLevel, deferred: true); // <-- The important bit
-
- public override void ChangeDatabase(string databaseName)
- => _inner.ChangeDatabase(databaseName);
-
- public override void Close()
- => _inner.Close();
-
- public override void Open()
- => _inner.Open();
+ public SqlitePreferDeferredTransactionsConnection(SqliteConnection inner) => _inner = inner;
public override string Database
=> _inner.Database;
@@ -38,9 +23,6 @@ public class SqlitePreferDeferredTransactionsConnection : DbConnection
public override string ServerVersion
=> _inner.ServerVersion;
- protected override DbCommand CreateDbCommand()
- => new CommandWrapper(_inner.CreateCommand());
-
[AllowNull]
public override string ConnectionString
{
@@ -48,26 +30,26 @@ public class SqlitePreferDeferredTransactionsConnection : DbConnection
set => _inner.ConnectionString = value;
}
+ protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
+ => _inner.BeginTransaction(isolationLevel, true); // <-- The important bit
+
+ public override void ChangeDatabase(string databaseName)
+ => _inner.ChangeDatabase(databaseName);
+
+ public override void Close()
+ => _inner.Close();
+
+ public override void Open()
+ => _inner.Open();
+
+ protected override DbCommand CreateDbCommand()
+ => new CommandWrapper(_inner.CreateCommand());
+
private class CommandWrapper : DbCommand
{
private readonly DbCommand _inner;
- public CommandWrapper(DbCommand inner)
- {
- _inner = inner;
- }
-
- public override void Cancel()
- => _inner.Cancel();
-
- public override int ExecuteNonQuery()
- => _inner.ExecuteNonQuery();
-
- public override object? ExecuteScalar()
- => _inner.ExecuteScalar();
-
- public override void Prepare()
- => _inner.Prepare();
+ public CommandWrapper(DbCommand inner) => _inner = inner;
[AllowNull]
public override string CommandText
@@ -97,10 +79,7 @@ public class SqlitePreferDeferredTransactionsConnection : DbConnection
protected override DbConnection? DbConnection
{
get => _inner.Connection;
- set
- {
- _inner.Connection = (value as SqlitePreferDeferredTransactionsConnection)?._inner;
- }
+ set => _inner.Connection = (value as SqlitePreferDeferredTransactionsConnection)?._inner;
}
protected override DbParameterCollection DbParameterCollection
@@ -118,6 +97,18 @@ public class SqlitePreferDeferredTransactionsConnection : DbConnection
set => _inner.DesignTimeVisible = value;
}
+ public override void Cancel()
+ => _inner.Cancel();
+
+ public override int ExecuteNonQuery()
+ => _inner.ExecuteNonQuery();
+
+ public override object? ExecuteScalar()
+ => _inner.ExecuteScalar();
+
+ public override void Prepare()
+ => _inner.Prepare();
+
protected override DbParameter CreateDbParameter()
=> _inner.CreateParameter();
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSpecificMapperFactory.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSpecificMapperFactory.cs
index cf1d707d69..66f542712a 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSpecificMapperFactory.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSpecificMapperFactory.cs
@@ -4,7 +4,7 @@ using Umbraco.Cms.Persistence.Sqlite.Mappers;
namespace Umbraco.Cms.Persistence.Sqlite.Services;
///
-/// Implements for SQLite.
+/// Implements for SQLite.
///
public class SqliteSpecificMapperFactory : IProviderSpecificMapperFactory
{
@@ -12,5 +12,5 @@ public class SqliteSpecificMapperFactory : IProviderSpecificMapperFactory
public string ProviderName => Constants.ProviderName;
///
- public NPocoMapperCollection Mappers => new NPocoMapperCollection(() => new[] { new SqlitePocoGuidMapper() });
+ public NPocoMapperCollection Mappers => new(() => new[] { new SqlitePocoGuidMapper() });
}
diff --git a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs
index 412be347a6..960ef4451c 100644
--- a/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs
+++ b/src/Umbraco.Cms.Persistence.Sqlite/Services/SqliteSyntaxProvider.cs
@@ -54,14 +54,12 @@ public class SqliteSyntaxProvider : SqlSyntaxProviderBase
///
public override string DbProvider => Constants.ProviderName;
-
///
public override bool SupportsIdentityInsert() => false;
///
public override bool SupportsClustered() => false;
-
public override string GetIndexType(IndexTypes indexTypes)
{
switch (indexTypes)
@@ -143,7 +141,9 @@ public class SqliteSyntaxProvider : SqlSyntaxProviderBase
public override string ConvertIntegerToOrderableString => "substr('0000000000'||'{0}', -10, 10)";
+
public override string ConvertDecimalToOrderableString => "substr('0000000000'||'{0}', -10, 10)";
+
public override string ConvertDateToOrderableString => "{0}";
///
@@ -153,16 +153,14 @@ public class SqliteSyntaxProvider : SqlSyntaxProviderBase
public override string GetSpecialDbType(SpecialDbType dbType, int customSize) => GetSpecialDbType(dbType);
///
- public override bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName,
- out string constraintName)
+ public override bool TryGetDefaultConstraint(IDatabase db, string? tableName, string columnName, out string constraintName)
{
// TODO: SQLite
constraintName = string.Empty;
return false;
}
- public override string GetFieldNameForUpdate(Expression> fieldSelector,
- string? tableAlias = null)
+ public override string GetFieldNameForUpdate