diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs
index 36da6007f6..622dcf564d 100644
--- a/src/Umbraco.Core/DatabaseContext.cs
+++ b/src/Umbraco.Core/DatabaseContext.cs
@@ -381,8 +381,6 @@ namespace Umbraco.Core
connString = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ConnectionString;
}
Initialize(providerName, connString);
-
- DetermineSqlServerVersion();
}
else if (ConfigurationManager.AppSettings.ContainsKey(GlobalSettings.UmbracoConnectionName) && string.IsNullOrEmpty(ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName]) == false)
{
@@ -419,8 +417,6 @@ namespace Umbraco.Core
//Remove the legacy connection string, so we don't end up in a loop if something goes wrong.
GlobalSettings.RemoveSetting(GlobalSettings.UmbracoConnectionName);
-
- DetermineSqlServerVersion();
}
else
{
@@ -465,48 +461,6 @@ namespace Umbraco.Core
Initialize(providerName);
}
- ///
- /// Set the lazy resolution of determining the SQL server version if that is the db type we're using
- ///
- private void DetermineSqlServerVersion()
- {
-
- var sqlServerSyntax = SqlSyntax as SqlServerSyntaxProvider;
- if (sqlServerSyntax != null)
- {
- //this will not execute now, it is lazy so will only execute when we need to actually know
- // the sql server version.
- sqlServerSyntax.VersionName = new Lazy(() =>
- {
- try
- {
- var database = this._factory.CreateDatabase();
-
- var version = database.ExecuteScalar("SELECT SERVERPROPERTY('productversion')");
- var firstPart = version.Split('.')[0];
- switch (firstPart)
- {
- case "11":
- return SqlServerVersionName.V2012;
- case "10":
- return SqlServerVersionName.V2008;
- case "9":
- return SqlServerVersionName.V2005;
- case "8":
- return SqlServerVersionName.V2000;
- case "7":
- return SqlServerVersionName.V7;
- default:
- return SqlServerVersionName.Other;
- }
- }
- catch (Exception)
- {
- return SqlServerVersionName.Invalid;
- }
- });
- }
- }
internal DatabaseSchemaResult ValidateDatabaseSchema()
{
diff --git a/src/Umbraco.Core/Persistence/PetaPoco.cs b/src/Umbraco.Core/Persistence/PetaPoco.cs
index 8a32deb331..4f0414ea3b 100644
--- a/src/Umbraco.Core/Persistence/PetaPoco.cs
+++ b/src/Umbraco.Core/Persistence/PetaPoco.cs
@@ -181,7 +181,7 @@ namespace Umbraco.Core.Persistence
CommonConstruct();
}
- enum DBType
+ internal enum DBType
{
SqlServer,
SqlServerCE,
@@ -726,6 +726,42 @@ namespace Umbraco.Core.Persistence
return true;
}
+ ///
+ /// NOTE: This is a custom mod of PetaPoco!! This builds the paging sql for different db providers
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal virtual void BuildSqlDbSpecificPagingQuery(DBType databaseType, long skip, long take, string sql, string sqlSelectRemoved, string sqlOrderBy, ref object[] args, out string sqlPage)
+ {
+ if (databaseType == DBType.SqlServer || databaseType == DBType.Oracle)
+ {
+ sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, "");
+ if (rxDistinct.IsMatch(sqlSelectRemoved))
+ {
+ sqlSelectRemoved = "peta_inner.* FROM (SELECT " + sqlSelectRemoved + ") peta_inner";
+ }
+ sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) peta_rn, {1}) peta_paged WHERE peta_rn>@{2} AND peta_rn<=@{3}",
+ sqlOrderBy == null ? "ORDER BY (SELECT NULL)" : sqlOrderBy, sqlSelectRemoved, args.Length, args.Length + 1);
+ args = args.Concat(new object[] { skip, skip + take }).ToArray();
+ }
+ else if (databaseType == DBType.SqlServerCE)
+ {
+ sqlPage = string.Format("{0}\nOFFSET @{1} ROWS FETCH NEXT @{2} ROWS ONLY", sql, args.Length, args.Length + 1);
+ args = args.Concat(new object[] { skip, take }).ToArray();
+ }
+ else
+ {
+ sqlPage = string.Format("{0}\nLIMIT @{1} OFFSET @{2}", sql, args.Length, args.Length + 1);
+ args = args.Concat(new object[] { take, skip }).ToArray();
+ }
+ }
+
public void BuildPageQueries(long skip, long take, string sql, ref object[] args, out string sqlCount, out string sqlPage)
{
// Add auto select clause
@@ -734,34 +770,12 @@ namespace Umbraco.Core.Persistence
// Split the SQL into the bits we need
string sqlSelectRemoved, sqlOrderBy;
- if (!SplitSqlForPaging(sql, out sqlCount, out sqlSelectRemoved, out sqlOrderBy))
+ if (SplitSqlForPaging(sql, out sqlCount, out sqlSelectRemoved, out sqlOrderBy) == false)
throw new Exception("Unable to parse SQL statement for paged query");
if (_dbType == DBType.Oracle && sqlSelectRemoved.StartsWith("*"))
throw new Exception("Query must alias '*' when performing a paged query.\neg. select t.* from table t order by t.id");
-
- // Build the SQL for the actual final result
- if (_dbType == DBType.SqlServer || _dbType == DBType.Oracle)
- {
- sqlSelectRemoved = rxOrderBy.Replace(sqlSelectRemoved, "");
- if (rxDistinct.IsMatch(sqlSelectRemoved))
- {
- sqlSelectRemoved = "peta_inner.* FROM (SELECT " + sqlSelectRemoved + ") peta_inner";
- }
- sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) peta_rn, {1}) peta_paged WHERE peta_rn>@{2} AND peta_rn<=@{3}",
- sqlOrderBy==null ? "ORDER BY (SELECT NULL)" : sqlOrderBy, sqlSelectRemoved, args.Length, args.Length + 1);
- args = args.Concat(new object[] { skip, skip+take }).ToArray();
- }
- else if (_dbType == DBType.SqlServerCE)
- {
- sqlPage = string.Format("{0}\nOFFSET @{1} ROWS FETCH NEXT @{2} ROWS ONLY", sql, args.Length, args.Length + 1);
- args = args.Concat(new object[] { skip, take }).ToArray();
- }
- else
- {
- sqlPage = string.Format("{0}\nLIMIT @{1} OFFSET @{2}", sql, args.Length, args.Length + 1);
- args = args.Concat(new object[] { take, skip }).ToArray();
- }
-
+
+ BuildSqlDbSpecificPagingQuery(_dbType, skip, take, sql, sqlSelectRemoved, sqlOrderBy, ref args, out sqlPage);
}
// Fetch a page
@@ -2315,8 +2329,8 @@ namespace Umbraco.Core.Persistence
// Member variables
- string _connectionString;
- string _providerName;
+ readonly string _connectionString;
+ readonly string _providerName;
DbProviderFactory _factory;
IDbConnection _sharedConnection;
IDbTransaction _transaction;
diff --git a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs
index 6b8e7b46ff..a72621d1a5 100644
--- a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs
+++ b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs
@@ -203,7 +203,8 @@ namespace Umbraco.Core.Persistence
{
//if it is sql ce or it is a sql server version less than 2008, we need to do individual inserts.
var sqlServerSyntax = SqlSyntaxContext.SqlSyntaxProvider as SqlServerSyntaxProvider;
- if ((sqlServerSyntax != null && (int)sqlServerSyntax.VersionName.Value < (int)SqlServerVersionName.V2008)
+
+ if ((sqlServerSyntax != null && (int)sqlServerSyntax.GetVersionName(db) < (int)SqlServerVersionName.V2008)
|| SqlSyntaxContext.SqlSyntaxProvider is SqlCeSyntaxProvider)
{
//SqlCe doesn't support bulk insert statements!
diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
index 57bc14aebf..2a873f01bb 100644
--- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
+++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs
@@ -14,12 +14,57 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public SqlServerSyntaxProvider()
{
- }
+ }
///
/// Gets/sets the version of the current SQL server instance
///
- internal Lazy VersionName { get; set; }
+ internal SqlServerVersionName GetVersionName(Database database)
+ {
+ if (_versionName.HasValue)
+ return _versionName.Value;
+
+ try
+ {
+ var version = database.ExecuteScalar("SELECT SERVERPROPERTY('productversion')");
+ var firstPart = version.Split('.')[0];
+ switch (firstPart)
+ {
+ case "13":
+ _versionName = SqlServerVersionName.V2014;
+ break;
+ case "12":
+ _versionName = SqlServerVersionName.V2014;
+ break;
+ case "11":
+ _versionName = SqlServerVersionName.V2012;
+ break;
+ case "10":
+ _versionName = SqlServerVersionName.V2008;
+ break;
+ case "9":
+ _versionName = SqlServerVersionName.V2005;
+ break;
+ case "8":
+ _versionName = SqlServerVersionName.V2000;
+ break;
+ case "7":
+ _versionName = SqlServerVersionName.V7;
+ break;
+ default:
+ _versionName = SqlServerVersionName.Other;
+ break;
+ }
+ }
+ catch (Exception)
+ {
+ _versionName = SqlServerVersionName.Invalid;
+ }
+
+ return _versionName.Value;
+ }
+
+ private SqlServerVersionName? _versionName;
///
/// SQL Server stores default values assigned to columns as constraints, it also stores them with named values, this is the only
diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerVersionName.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerVersionName.cs
index 37870a9536..2f50f39435 100644
--- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerVersionName.cs
+++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerVersionName.cs
@@ -3,6 +3,9 @@
///
/// Represents the version name of SQL server (i.e. the year 2008, 2005, etc...)
///
+ ///
+ /// see: https://support.microsoft.com/en-us/kb/321185
+ ///
internal enum SqlServerVersionName
{
Invalid = -1,
@@ -11,6 +14,8 @@
V2005 = 2,
V2008 = 3,
V2012 = 4,
- Other = 5
+ V2014 = 5,
+ V2016 = 6,
+ Other = 100
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs
index a0490348f3..5ca30f2860 100644
--- a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs
+++ b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Text;
using StackExchange.Profiling;
using Umbraco.Core.Logging;
+using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence
{
@@ -154,5 +155,41 @@ namespace Umbraco.Core.Persistence
}
base.OnExecutedCommand(cmd);
}
+
+ ///
+ /// We are overriding this in the case that we are using SQL Server 2012+ so we can make paging more efficient than the default PetaPoco paging
+ /// see: http://issues.umbraco.org/issue/U4-8837
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal override void BuildSqlDbSpecificPagingQuery(DBType databaseType, long skip, long take, string sql, string sqlSelectRemoved, string sqlOrderBy, ref object[] args, out string sqlPage)
+ {
+ if (databaseType == DBType.SqlServer)
+ {
+ //we need to check it's version to see what kind of paging format we can use
+ //TODO: This is a hack, but we don't have access to the SqlSyntaxProvider here, we can in v8 but not now otherwise
+ // this would be a breaking change.
+ var sqlServerSyntax = SqlSyntaxContext.SqlSyntaxProvider as SqlServerSyntaxProvider;
+ if (sqlServerSyntax != null)
+ {
+ if ((int) sqlServerSyntax.GetVersionName(this) >= (int) SqlServerVersionName.V2012)
+ {
+ //we can use the good paging! to do that we are going to change the databaseType to SQLCE since
+ //it also uses the good paging syntax.
+ base.BuildSqlDbSpecificPagingQuery(DBType.SqlServerCE, skip, take, sql, sqlSelectRemoved, sqlOrderBy, ref args, out sqlPage);
+ return;
+ }
+ }
+ }
+
+ //use the defaults
+ base.BuildSqlDbSpecificPagingQuery(databaseType, skip, take, sql, sqlSelectRemoved, sqlOrderBy, ref args, out sqlPage);
+ }
}
}
\ No newline at end of file