Fixes upgrade issues with SQLCE and DateTime:

* DateTime's during migrations are formatted in a very explicit way
* Migration's that need to execute multiple statements are fixed in SQLCE by splitting on GO
This commit is contained in:
Shannon
2015-09-11 13:55:13 +02:00
parent 4bb89c1827
commit 488ba05eda
6 changed files with 79 additions and 19 deletions

View File

@@ -77,9 +77,9 @@ namespace Umbraco.Core.Persistence.Migrations
case TypeCode.UInt64:
return val.ToString();
case TypeCode.DateTime:
return SqlSyntax.FormatDateTime((DateTime) val);
return SqlSyntax.GetQuotedValue(SqlSyntax.FormatDateTime((DateTime) val));
default:
return SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(val.ToString());
return SqlSyntax.GetQuotedValue(val.ToString());
}
}
}

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using log4net;
using Semver;
using Umbraco.Core.Configuration;
@@ -243,13 +245,43 @@ namespace Umbraco.Core.Persistence.Migrations
//TODO: We should output all of these SQL calls to files in a migration folder in App_Data/TEMP
// so if people want to executed them manually on another environment, they can.
_logger.Info<MigrationRunner>("Executing sql statement " + i + ": " + sql);
database.Execute(sql);
//The following ensures the multiple statement sare executed one at a time, this is a requirement
// of SQLCE, it's unfortunate but necessary.
// http://stackoverflow.com/questions/13665491/sql-ce-inconsistent-with-multiple-statements
var sb = new StringBuilder();
using (var reader = new StringReader(sql))
{
string line;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Equals("GO", StringComparison.OrdinalIgnoreCase))
{
//Execute the SQL up to the point of a GO statement
var exeSql = sb.ToString();
_logger.Info<MigrationRunner>("Executing sql statement " + i + ": " + exeSql);
database.Execute(exeSql);
//restart the string builder
sb.Remove(0, sb.Length);
}
else
{
sb.AppendLine(line);
}
}
//execute anything remaining
if (sb.Length > 0)
{
var exeSql = sb.ToString();
_logger.Info<MigrationRunner>("Executing sql statement " + i + ": " + exeSql);
database.Execute(exeSql);
}
}
i++;
}
transaction.Complete();
//Now that this is all complete, we need to add an entry to the migrations table flagging that migrations

View File

@@ -41,13 +41,16 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Insert.Expressions
{
if (IsExpressionSupported() == false)
return string.Empty;
var insertItems = new List<string>();
var sb = new StringBuilder();
if (EnabledIdentityInsert && SqlSyntax.SupportsIdentityInsert())
{
sb.AppendLine(string.Format("SET IDENTITY_INSERT {0} ON;", SqlSyntax.GetQuotedTableName(TableName)));
if (SqlSyntax.GetType() != typeof (MySqlSyntaxProvider))
{
sb.AppendLine("GO");
}
}
try
@@ -69,16 +72,22 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Insert.Expressions
SqlSyntax.GetQuotedTableName(TableName),
cols, vals);
insertItems.Add(sql);
sb.AppendLine(string.Format("{0};", sql));
if (SqlSyntax.GetType() != typeof(MySqlSyntaxProvider))
{
sb.AppendLine("GO");
}
}
sb.AppendLine(string.Join(",", insertItems));
}
finally
{
if (EnabledIdentityInsert && SqlSyntax.SupportsIdentityInsert())
{
sb.AppendLine(string.Format(";SET IDENTITY_INSERT {0} OFF;", SqlSyntax.GetQuotedTableName(TableName)));
sb.AppendLine(string.Format("SET IDENTITY_INSERT {0} OFF;", SqlSyntax.GetQuotedTableName(TableName)));
if (SqlSyntax.GetType() != typeof(MySqlSyntaxProvider))
{
sb.AppendLine("GO");
}
}
}

View File

@@ -38,11 +38,30 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenThreeZe
SqlSyntax.GetQuotedColumnName("master") + @" NOT IN (SELECT nodeId FROM cmsTemplate)");
//Now we can bulk update the parentId column
Execute.Sql(@"UPDATE umbracoNode
SET parentID = COALESCE(t2." + SqlSyntax.GetQuotedColumnName("master") + @", -1)
FROM umbracoNode t1
INNER JOIN cmsTemplate t2
ON t1.id = t2.nodeId");
//NOTE: This single statement should be used but stupid SQLCE doesn't support Update with a FROM !!
// so now we have to do this by individual rows :(
//Execute.Sql(@"UPDATE umbracoNode
//SET parentID = COALESCE(t2." + SqlSyntax.GetQuotedColumnName("master") + @", -1)
//FROM umbracoNode t1
//INNER JOIN cmsTemplate t2
//ON t1.id = t2.nodeId");
Execute.Code(database =>
{
var templateData = database.Fetch<dynamic>("SELECT * FROM cmsTemplate");
foreach (var template in templateData)
{
var sql = "SET parentID=@parentId WHERE id=@nodeId";
LogHelper.Info<MigrateAndRemoveTemplateMasterColumn>("Executing sql statement: UPDATE umbracoNode " + sql);
database.Update<NodeDto>(sql,
new {parentId = template.master ?? -1, nodeId = template.nodeId});
}
return string.Empty;
});
//Now we can update the path, but this needs to be done in a delegate callback so that the query runs after the updates just completed
Execute.Code(database =>

View File

@@ -203,7 +203,7 @@ ORDER BY TABLE_NAME, INDEX_NAME",
/// </remarks>
public override string FormatDateTime(DateTime date, bool includeTime = true)
{
return includeTime ? date.ToString("YYYYMMDDHHmmss") : date.ToString("YYYYMMDD");
return includeTime ? date.ToString("yyyyMMddHHmmss") : date.ToString("yyyyMMdd");
}
public override string GetQuotedTableName(string tableName)

View File

@@ -263,7 +263,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
/// </remarks>
public virtual string FormatDateTime(DateTime date, bool includeTime = true)
{
return includeTime ? date.ToString("YYYYMMDD HH:mm:ss") : date.ToString("YYYYMMDD");
return includeTime ? date.ToString("yyyyMMdd HH:mm:ss") : date.ToString("yyyyMMdd");
}
public virtual string Format(TableDefinition table)