diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs index e074297eb8..2bc46688f2 100644 --- a/src/Umbraco.Core/DatabaseContext.cs +++ b/src/Umbraco.Core/DatabaseContext.cs @@ -3,6 +3,7 @@ using System.Configuration; using System.Data.SqlServerCe; using System.IO; using System.Linq; +using System.Web; using System.Web.Configuration; using System.Xml.Linq; using Umbraco.Core.Configuration; @@ -426,6 +427,13 @@ namespace Umbraco.Core if (_result == null) { + + if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted + && ProviderName == "MySql.Data.MySqlClient") + { + throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration"); + } + var database = new UmbracoDatabase(_connectionString, ProviderName); var dbSchema = new DatabaseSchemaCreation(database); _result = dbSchema.ValidateSchema(); @@ -434,15 +442,15 @@ namespace Umbraco.Core } internal Result CreateDatabaseSchemaAndData() - { - var readyForInstall = CheckReadyForInstall(); - if (readyForInstall.Success == false) - { - return readyForInstall.Result; - } - + { try { + var readyForInstall = CheckReadyForInstall(); + if (readyForInstall.Success == false) + { + return readyForInstall.Result; + } + LogHelper.Info("Database configuration status: Started"); string message; @@ -500,14 +508,15 @@ namespace Umbraco.Core /// internal Result UpgradeSchemaAndData() { - var readyForInstall = CheckReadyForInstall(); - if (readyForInstall.Success == false) - { - return readyForInstall.Result; - } - try { + + var readyForInstall = CheckReadyForInstall(); + if (readyForInstall.Success == false) + { + return readyForInstall.Result; + } + LogHelper.Info("Database upgrade started"); var database = new UmbracoDatabase(_connectionString, ProviderName); @@ -567,6 +576,12 @@ namespace Umbraco.Core private Attempt CheckReadyForInstall() { + if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted + && ProviderName == "MySql.Data.MySqlClient") + { + throw new InvalidOperationException("Cannot use MySql in Medium Trust configuration"); + } + if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName))) { return Attempt.Fail(new Result diff --git a/src/Umbraco.Core/Persistence/Migrations/CatastrophicDataLossException.cs b/src/Umbraco.Core/Persistence/Migrations/CatastrophicDataLossException.cs new file mode 100644 index 0000000000..9c425a9e82 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/CatastrophicDataLossException.cs @@ -0,0 +1,22 @@ +using System; + +namespace Umbraco.Core.Persistence.Migrations +{ + /// + /// Used if a migration has executed but the whole process has failed and cannot be rolled back + /// + internal class CatastrophicDataLossException : Exception + { + public CatastrophicDataLossException(string msg) + : base(msg) + { + + } + + public CatastrophicDataLossException(string msg, Exception inner) + : base(msg, inner) + { + + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs index 27acb334c4..0220e146b0 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaCreation.cs @@ -141,50 +141,31 @@ namespace Umbraco.Core.Persistence.Migrations.Initial result.TableDefinitions.Add(tableDefinition); } - //Check tables in configured database against tables in schema - var tablesInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetTablesInSchema(_database).ToList(); - var tablesInSchema = result.TableDefinitions.Select(x => x.Name).ToList(); - //Add valid and invalid table differences to the result object - var validTableDifferences = tablesInDatabase.Intersect(tablesInSchema, StringComparer.InvariantCultureIgnoreCase); - foreach (var tableName in validTableDifferences) - { - result.ValidTables.Add(tableName); - } - var invalidTableDifferences = - tablesInDatabase.Except(tablesInSchema, StringComparer.InvariantCultureIgnoreCase) - .Union(tablesInSchema.Except(tablesInDatabase, StringComparer.InvariantCultureIgnoreCase)); - foreach (var tableName in invalidTableDifferences) - { - result.Errors.Add(new Tuple("Table", tableName)); - } + ValidateDbTables(result); - //Check columns in configured database against columns in schema - var columnsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetColumnsInSchema(_database); - var columnsPerTableInDatabase = columnsInDatabase.Select(x => string.Concat(x.TableName, ",", x.ColumnName)).ToList(); - var columnsPerTableInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => string.Concat(y.TableName, ",", y.Name))).ToList(); - //Add valid and invalid column differences to the result object - var validColumnDifferences = columnsPerTableInDatabase.Intersect(columnsPerTableInSchema, StringComparer.InvariantCultureIgnoreCase); - foreach (var column in validColumnDifferences) - { - result.ValidColumns.Add(column); - } - var invalidColumnDifferences = columnsPerTableInDatabase.Except(columnsPerTableInSchema, StringComparer.InvariantCultureIgnoreCase); - foreach (var column in invalidColumnDifferences) - { - result.Errors.Add(new Tuple("Column", column)); - } + ValidateDbColumns(result); + ValidateDbIndexes(result); + + ValidateDbConstraints(result); + + return result; + } + + private void ValidateDbConstraints(DatabaseSchemaResult result) + { //MySql doesn't conform to the "normal" naming of constraints, so there is currently no point in doing these checks. //TODO: At a later point we do other checks for MySql, but ideally it should be necessary to do special checks for different providers. // ALso note that to get the constraints for MySql we have to open a connection which we currently have not. if (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider) - return result; + return; //Check constraints in configured database against constraints in schema var constraintsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetConstraintsPerColumn(_database).DistinctBy(x => x.Item3).ToList(); var foreignKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("FK_")).Select(x => x.Item3).ToList(); var primaryKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("PK_")).Select(x => x.Item3).ToList(); var indexesInDatabase = constraintsInDatabase.Where(x => x.Item3.InvariantStartsWith("IX_")).Select(x => x.Item3).ToList(); + var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList(); var unknownConstraintsInDatabase = constraintsInDatabase.Where( x => @@ -192,7 +173,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial x.Item3.InvariantStartsWith("IX_") == false).Select(x => x.Item3).ToList(); var foreignKeysInSchema = result.TableDefinitions.SelectMany(x => x.ForeignKeys.Select(y => y.Name)).ToList(); var primaryKeysInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => y.PrimaryKeyName)).ToList(); - var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList(); + //Add valid and invalid foreign key differences to the result object foreach (var unknown in unknownConstraintsInDatabase) { @@ -205,40 +186,121 @@ namespace Umbraco.Core.Persistence.Migrations.Initial result.Errors.Add(new Tuple("Unknown", unknown)); } } + + //Foreign keys: + var validForeignKeyDifferences = foreignKeysInDatabase.Intersect(foreignKeysInSchema, StringComparer.InvariantCultureIgnoreCase); foreach (var foreignKey in validForeignKeyDifferences) { result.ValidConstraints.Add(foreignKey); } - var invalidForeignKeyDifferences = foreignKeysInDatabase.Except(foreignKeysInSchema, StringComparer.InvariantCultureIgnoreCase); + var invalidForeignKeyDifferences = + foreignKeysInDatabase.Except(foreignKeysInSchema, StringComparer.InvariantCultureIgnoreCase) + .Union(foreignKeysInSchema.Except(foreignKeysInDatabase, StringComparer.InvariantCultureIgnoreCase)); foreach (var foreignKey in invalidForeignKeyDifferences) { result.Errors.Add(new Tuple("Constraint", foreignKey)); } + + + //Primary keys: + //Add valid and invalid primary key differences to the result object var validPrimaryKeyDifferences = primaryKeysInDatabase.Intersect(primaryKeysInSchema, StringComparer.InvariantCultureIgnoreCase); foreach (var primaryKey in validPrimaryKeyDifferences) { result.ValidConstraints.Add(primaryKey); } - var invalidPrimaryKeyDifferences = primaryKeysInDatabase.Except(primaryKeysInSchema, StringComparer.InvariantCultureIgnoreCase); + var invalidPrimaryKeyDifferences = + primaryKeysInDatabase.Except(primaryKeysInSchema, StringComparer.InvariantCultureIgnoreCase) + .Union(primaryKeysInSchema.Except(primaryKeysInDatabase, StringComparer.InvariantCultureIgnoreCase)); foreach (var primaryKey in invalidPrimaryKeyDifferences) { result.Errors.Add(new Tuple("Constraint", primaryKey)); } + + //Constaints: + + //NOTE: SD: The colIndex checks above should really take care of this but I need to keep this here because it was here before + // and some schema validation checks might rely on this data remaining here! //Add valid and invalid index differences to the result object var validIndexDifferences = indexesInDatabase.Intersect(indexesInSchema, StringComparer.InvariantCultureIgnoreCase); foreach (var index in validIndexDifferences) { result.ValidConstraints.Add(index); } - var invalidIndexDifferences = indexesInDatabase.Except(indexesInSchema, StringComparer.InvariantCultureIgnoreCase); + var invalidIndexDifferences = + indexesInDatabase.Except(indexesInSchema, StringComparer.InvariantCultureIgnoreCase) + .Union(indexesInSchema.Except(indexesInDatabase, StringComparer.InvariantCultureIgnoreCase)); foreach (var index in invalidIndexDifferences) { result.Errors.Add(new Tuple("Constraint", index)); } + } - return result; + private void ValidateDbColumns(DatabaseSchemaResult result) + { + //Check columns in configured database against columns in schema + var columnsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetColumnsInSchema(_database); + var columnsPerTableInDatabase = columnsInDatabase.Select(x => string.Concat(x.TableName, ",", x.ColumnName)).ToList(); + var columnsPerTableInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => string.Concat(y.TableName, ",", y.Name))).ToList(); + //Add valid and invalid column differences to the result object + var validColumnDifferences = columnsPerTableInDatabase.Intersect(columnsPerTableInSchema, StringComparer.InvariantCultureIgnoreCase); + foreach (var column in validColumnDifferences) + { + result.ValidColumns.Add(column); + } + + var invalidColumnDifferences = + columnsPerTableInDatabase.Except(columnsPerTableInSchema, StringComparer.InvariantCultureIgnoreCase) + .Union(columnsPerTableInSchema.Except(columnsPerTableInDatabase, StringComparer.InvariantCultureIgnoreCase)); + foreach (var column in invalidColumnDifferences) + { + result.Errors.Add(new Tuple("Column", column)); + } + } + + private void ValidateDbTables(DatabaseSchemaResult result) + { + //Check tables in configured database against tables in schema + var tablesInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetTablesInSchema(_database).ToList(); + var tablesInSchema = result.TableDefinitions.Select(x => x.Name).ToList(); + //Add valid and invalid table differences to the result object + var validTableDifferences = tablesInDatabase.Intersect(tablesInSchema, StringComparer.InvariantCultureIgnoreCase); + foreach (var tableName in validTableDifferences) + { + result.ValidTables.Add(tableName); + } + + var invalidTableDifferences = + tablesInDatabase.Except(tablesInSchema, StringComparer.InvariantCultureIgnoreCase) + .Union(tablesInSchema.Except(tablesInDatabase, StringComparer.InvariantCultureIgnoreCase)); + foreach (var tableName in invalidTableDifferences) + { + result.Errors.Add(new Tuple("Table", tableName)); + } + } + + private void ValidateDbIndexes(DatabaseSchemaResult result) + { + //These are just column indexes NOT constraints or Keys + var colIndexesInDatabase = result.DbIndexDefinitions.Where(x => x.IndexName.InvariantStartsWith("IX_")).Select(x => x.IndexName).ToList(); + var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList(); + + //Add valid and invalid index differences to the result object + var validColIndexDifferences = colIndexesInDatabase.Intersect(indexesInSchema, StringComparer.InvariantCultureIgnoreCase); + foreach (var index in validColIndexDifferences) + { + result.ValidIndexes.Add(index); + } + + var invalidColIndexDifferences = + colIndexesInDatabase.Except(indexesInSchema, StringComparer.InvariantCultureIgnoreCase) + .Union(indexesInSchema.Except(colIndexesInDatabase, StringComparer.InvariantCultureIgnoreCase)); + foreach (var index in invalidColIndexDifferences) + { + result.Errors.Add(new Tuple("Index", index)); + } } #region Events diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs index 49f9746b7c..4db0f7222a 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/DatabaseSchemaResult.cs @@ -17,6 +17,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial ValidTables = new List(); ValidColumns = new List(); ValidConstraints = new List(); + ValidIndexes = new List(); } public List> Errors { get; set; } @@ -29,6 +30,8 @@ namespace Umbraco.Core.Persistence.Migrations.Initial public List ValidConstraints { get; set; } + public List ValidIndexes { get; set; } + internal IEnumerable DbIndexDefinitions { get; set; } /// @@ -45,7 +48,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial return new Version(0, 0, 0); //If Errors is empty or if TableDefinitions tables + columns correspond to valid tables + columns then we're at current version - if (!Errors.Any() || + if (Errors.Any() == false || (TableDefinitions.All(x => ValidTables.Contains(x.Name)) && TableDefinitions.SelectMany(definition => definition.Columns).All(x => ValidColumns.Contains(x.Name)))) return UmbracoVersion.Current; @@ -71,6 +74,12 @@ namespace Umbraco.Core.Persistence.Migrations.Initial return new Version(6, 0, 0); } + //if the error is for an index + if (Errors.Any(x => x.Item1.Equals("Index") && (x.Item2.InvariantEquals("IX_umbracoNodeTrashed")))) + { + return new Version(6, 1, 0); + } + return UmbracoVersion.Current; } @@ -108,6 +117,13 @@ namespace Umbraco.Core.Persistence.Migrations.Initial sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Constraint")).Select(x => x.Item2))); sb.AppendLine(" "); } + //Index error summary + if (Errors.Any(x => x.Item1.Equals("Index"))) + { + sb.AppendLine("The following indexes were found in the database, but are not in the current schema:"); + sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Index")).Select(x => x.Item2))); + sb.AppendLine(" "); + } //Unknown constraint error summary if (Errors.Any(x => x.Item1.Equals("Unknown"))) { diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs index b815896539..f49bea5ce0 100644 --- a/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationAttribute.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.Persistence.Migrations /// database migrations with Up/Down methods for pushing changes UP or pulling them DOWN. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - public class MigrationAttribute : Attribute + public sealed class MigrationAttribute : Attribute { public MigrationAttribute(string targetVersion, int sortOrder, string product) { diff --git a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs index a988d77740..b4117003fb 100644 --- a/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs +++ b/src/Umbraco.Core/Persistence/Migrations/MigrationRunner.cs @@ -3,10 +3,11 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core.Events; using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.Migrations.Syntax.IfDatabase; namespace Umbraco.Core.Persistence.Migrations { - /// + /// /// Represents the Migration Runner, which is used to apply migrations to /// the umbraco database. /// @@ -45,19 +46,62 @@ namespace Umbraco.Core.Persistence.Migrations { LogHelper.Info("Initializing database migrations"); - var foundMigrations = MigrationResolver.Current.Migrations; + var foundMigrations = MigrationResolver.Current.Migrations.ToArray(); - var migrations = isUpgrade - ? OrderedUpgradeMigrations(foundMigrations).ToList() - : OrderedDowngradeMigrations(foundMigrations).ToList(); + //filter all schema migrations + var schemaMigrations = isUpgrade + ? OrderedUpgradeMigrations(foundMigrations.Where(x => (x is SchemaMigration))).ToList() + : OrderedDowngradeMigrations(foundMigrations.Where(x => (x is SchemaMigration))).ToList(); + + //filter all non-schema migrations + var dataMigrations = isUpgrade + ? OrderedUpgradeMigrations(foundMigrations.Where(x => (x is SchemaMigration) == false)).ToList() + : OrderedDowngradeMigrations(foundMigrations.Where(x => (x is SchemaMigration) == false)).ToList(); //SD: Why do we want this? - if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _configuredVersion, _targetVersion, true), this)) + if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(dataMigrations, _configuredVersion, _targetVersion, true), this)) return false; //Loop through migrations to generate sql - var context = ExecuteMigrations(migrations, database, databaseProvider, isUpgrade); + var schemaMigrationContext = InitializeMigrations(schemaMigrations, database, databaseProvider, isUpgrade); + + try + { + ExecuteMigrations(schemaMigrationContext, database); + } + catch (Exception) + { + //if this fails then the transaction will be rolled back, BUT if we are using MySql this is not the case, + //since it does not support schema changes in a transaction, see: http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html + //so in that case we have to downgrade + if (databaseProvider == DatabaseProviders.MySql) + { + var downgrades = OrderedDowngradeMigrations(foundMigrations.Where(x => (x is SchemaMigration))).ToList(); + var downgradeMigrationContext = InitializeMigrations(downgrades, database, databaseProvider, false); + //lets hope that works! - if something cannot be rolled back then a CatastrophicDataLossException should + // be thrown. + ExecuteMigrations(downgradeMigrationContext, database); + } + + //continue throwing the exception + throw; + } + + //Ok, we've made it this far, now we can execute our data migrations + + //Loop through migrations to generate sql + var dataMigrationContext = InitializeMigrations(dataMigrations, database, databaseProvider, isUpgrade); + //run them - if this fails the data will be rolled back + ExecuteMigrations(dataMigrationContext, database); + + Migrated.RaiseEvent(new MigrationEventArgs(dataMigrations, dataMigrationContext, _configuredVersion, _targetVersion, false), this); + + return true; + } + + private void ExecuteMigrations(IMigrationContext context, Database database) + { //Transactional execution of the sql that was generated from the found migrations using (var transaction = database.GetTransaction()) { @@ -78,13 +122,9 @@ namespace Umbraco.Core.Persistence.Migrations transaction.Complete(); } + } - Migrated.RaiseEvent(new MigrationEventArgs(migrations, context, _configuredVersion, _targetVersion, false), this); - - return true; - } - - internal MigrationContext ExecuteMigrations(List migrations, Database database, DatabaseProviders databaseProvider, bool isUpgrade = true) + internal MigrationContext InitializeMigrations(List migrations, Database database, DatabaseProviders databaseProvider, bool isUpgrade = true) { //Loop through migrations to generate sql var context = new MigrationContext(databaseProvider, database); diff --git a/src/Umbraco.Core/Persistence/Migrations/SchemaMigration.cs b/src/Umbraco.Core/Persistence/Migrations/SchemaMigration.cs new file mode 100644 index 0000000000..6c1e9301ae --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/SchemaMigration.cs @@ -0,0 +1,11 @@ +namespace Umbraco.Core.Persistence.Migrations +{ + /// + /// A migration class that specifies that it is used for db schema migrations only - these need to execute first and MUST + /// have a downgrade plan. + /// + public abstract class SchemaMigration : MigrationBase + { + + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourNineZero/RemoveUmbracoAppConstraints.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourNineZero/RemoveUmbracoAppConstraints.cs index efcb5d2415..e7543fd063 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourNineZero/RemoveUmbracoAppConstraints.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourNineZero/RemoveUmbracoAppConstraints.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Configuration; namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero { [MigrationAttribute("4.9.0", 0, GlobalSettings.UmbracoMigrationName)] - public class RemoveUmbracoAppConstraints : MigrationBase + public class RemoveUmbracoAppConstraints : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/DeleteAppTables.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/DeleteAppTables.cs index 567f641e5c..fe0820a025 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/DeleteAppTables.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/DeleteAppTables.cs @@ -2,6 +2,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { + [Migration("6.0.0", 10, GlobalSettings.UmbracoMigrationName)] public class DeleteAppTables : MigrationBase { @@ -14,6 +15,8 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix public override void Down() { + //This cannot be rolled back!! + throw new CatastrophicDataLossException("Cannot rollback migration " + typeof(DeleteAppTables) + " the db tables umbracoAppTree and umbracoApp have been droppped"); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/NewCmsContentType2ContentTypeTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/NewCmsContentType2ContentTypeTable.cs index 7ff03087c4..29fb8c0f6d 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/NewCmsContentType2ContentTypeTable.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/NewCmsContentType2ContentTypeTable.cs @@ -3,7 +3,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { [Migration("6.0.0", 4, GlobalSettings.UmbracoMigrationName)] - public class NewCmsContentType2ContentTypeTable : MigrationBase + public class NewCmsContentType2ContentTypeTable : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RemoveMasterContentTypeColumn.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RemoveMasterContentTypeColumn.cs index 680b2001a0..b11c32e818 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RemoveMasterContentTypeColumn.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RemoveMasterContentTypeColumn.cs @@ -3,7 +3,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { [Migration("6.0.0", 6, GlobalSettings.UmbracoMigrationName)] - public class RemoveMasterContentTypeColumn : MigrationBase + public class RemoveMasterContentTypeColumn : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameCmsTabTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameCmsTabTable.cs index 0f8635af09..daf5400c81 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameCmsTabTable.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameCmsTabTable.cs @@ -3,7 +3,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { [Migration("6.0.0", 0, GlobalSettings.UmbracoMigrationName)] - public class RenameCmsTabTable : MigrationBase + public class RenameCmsTabTable : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameTabIdColumn.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameTabIdColumn.cs index 6f3f7edc80..7ff33092b0 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameTabIdColumn.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/RenameTabIdColumn.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Configuration; namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { [Migration("6.0.0", 7, GlobalSettings.UmbracoMigrationName)] - public class RenameTabIdColumn : MigrationBase + public class RenameTabIdColumn : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeAllowedContentTypeTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeAllowedContentTypeTable.cs index be704466a8..0d9ddef431 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeAllowedContentTypeTable.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeAllowedContentTypeTable.cs @@ -3,7 +3,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { [Migration("6.0.0", 3, GlobalSettings.UmbracoMigrationName)] - public class UpdateCmsContentTypeAllowedContentTypeTable : MigrationBase + public class UpdateCmsContentTypeAllowedContentTypeTable : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeTable.cs index 3e6b4cf05c..935b6f62bf 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeTable.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentTypeTable.cs @@ -3,7 +3,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { [Migration("6.0.0", 2, GlobalSettings.UmbracoMigrationName)] - public class UpdateCmsContentTypeTable : MigrationBase + public class UpdateCmsContentTypeTable : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentVersionTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentVersionTable.cs index 1dc8998e68..e84383d753 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentVersionTable.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsContentVersionTable.cs @@ -3,7 +3,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { [Migration("6.0.0", 8, GlobalSettings.UmbracoMigrationName)] - public class UpdateCmsContentVersionTable : MigrationBase + public class UpdateCmsContentVersionTable : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsPropertyTypeGroupTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsPropertyTypeGroupTable.cs index 2bd03f15bc..ab7f0fa5c1 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsPropertyTypeGroupTable.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSix/UpdateCmsPropertyTypeGroupTable.cs @@ -4,7 +4,7 @@ using Umbraco.Core.Configuration; namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix { [Migration("6.0.0", 1, GlobalSettings.UmbracoMigrationName)] - public class UpdateCmsPropertyTypeGroupTable : MigrationBase + public class UpdateCmsPropertyTypeGroupTable : SchemaMigration { public override void Up() { diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixOneZero/CreateServerRegistryTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixOneZero/CreateServerRegistryTable.cs index 757e5fd4f0..e54e43761d 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixOneZero/CreateServerRegistryTable.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixOneZero/CreateServerRegistryTable.cs @@ -9,15 +9,17 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixOneZero { [Migration("6.1.0", 0, GlobalSettings.UmbracoMigrationName)] - public class CreateServerRegistryTable : MigrationBase + public class CreateServerRegistryTable : SchemaMigration { public override void Up() { - base.Context.Database.CreateTable(); + //NOTE: This isn't the correct way to do this but to manually create this table with the Create syntax is a pain in the arse + Context.Database.CreateTable(); } public override void Down() { + Delete.Table("umbracoServer"); } } } diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs index 884829affc..146124dccb 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/AdditionalIndexesAndKeys.cs @@ -8,7 +8,7 @@ using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero { [Migration("6.2.0", 0, GlobalSettings.UmbracoMigrationName)] - public class AdditionalIndexesAndKeys : MigrationBase + public class AdditionalIndexesAndKeys : SchemaMigration { public override void Up() { @@ -44,22 +44,10 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero public override void Down() { - throw new NotImplementedException(); - } - } - - [Migration("6.2.0", 2, GlobalSettings.UmbracoMigrationName)] - public class ChangePasswordColumn : MigrationBase - { - public override void Up() - { - //up to 500 chars - Alter.Table("umbracoUser").AlterColumn("userPassword").AsString(500).NotNullable(); - } - - public override void Down() - { - throw new NotImplementedException(); + Delete.Index("IX_umbracoNodeTrashed").OnTable("umbracoNode"); + Delete.Index("IX_cmsContentVersion_ContentId").OnTable("cmsContentVersion"); + Delete.Index("IX_cmsDocument_published").OnTable("cmsDocument"); + Delete.Index("IX_cmsDocument_newest").OnTable("cmsDocument"); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/ChangePasswordColumn.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/ChangePasswordColumn.cs new file mode 100644 index 0000000000..545e74f1e6 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/ChangePasswordColumn.cs @@ -0,0 +1,21 @@ +using System; +using Umbraco.Core.Configuration; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero +{ + [Migration("6.2.0", 2, GlobalSettings.UmbracoMigrationName)] + public class ChangePasswordColumn : SchemaMigration + { + public override void Up() + { + //up to 500 chars + Alter.Table("umbracoUser").AlterColumn("userPassword").AsString(500).NotNullable(); + } + + public override void Down() + { + //back to 125 chars + Alter.Table("umbracoUser").AlterColumn("userPassword").AsString(125).NotNullable(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/UpdateToNewMemberPropertyAliases.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/UpdateToNewMemberPropertyAliases.cs index abc312ab5d..66be6bbe30 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/UpdateToNewMemberPropertyAliases.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSixTwoZero/UpdateToNewMemberPropertyAliases.cs @@ -34,10 +34,10 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixTwoZero const string propertyTypeUpdateSql = @"UPDATE cmsPropertyType SET Alias = @newAlias WHERE Alias = @oldAlias AND contentTypeId IN ( -SELECT DISTINCT cmsContentType.nodeId FROM cmsPropertyType +SELECT nodeId FROM (SELECT DISTINCT cmsContentType.nodeId FROM cmsPropertyType INNER JOIN cmsContentType ON cmsPropertyType.contentTypeId = cmsContentType.nodeId INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id -WHERE umbracoNode.nodeObjectType = @objectType)"; +WHERE umbracoNode.nodeObjectType = @objectType) x)"; const string xmlSelectSql = @"SELECT cmsContentXml.* FROM cmsContentXml INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs index f50b864203..7e8d7b7566 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntaxProvider.cs @@ -134,10 +134,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax db.OpenSharedConnection(); var indexes = - db.Fetch(@"SELECT DISTINCT - TABLE_NAME, INDEX_NAME, COLUMN_NAME, CASE NON_UNIQUE WHEN 1 THEN 0 ELSE 1 END AS `UNIQUE` -FROM INFORMATION_SCHEMA.STATISTICS + db.Fetch(@"SELECT DISTINCT + TABLE_NAME, INDEX_NAME, COLUMN_NAME, CASE NON_UNIQUE WHEN 1 THEN 0 ELSE 1 END AS `UNIQUE` +FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = @TableSchema +AND INDEX_NAME <> COLUMN_NAME AND INDEX_NAME <> 'PRIMARY' ORDER BY TABLE_NAME, INDEX_NAME", new { TableSchema = db.Connection.Database }); list = diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs index 769d5547f4..170b10cb5e 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntaxProvider.cs @@ -230,7 +230,9 @@ namespace Umbraco.Core.Persistence.SqlSyntax { var items = db.Fetch( - "SELECT TABLE_NAME, INDEX_NAME, COLUMN_NAME, [UNIQUE] FROM INFORMATION_SCHEMA.INDEXES ORDER BY TABLE_NAME, INDEX_NAME"); + @"SELECT TABLE_NAME, INDEX_NAME, COLUMN_NAME, [UNIQUE] FROM INFORMATION_SCHEMA.INDEXES +WHERE INDEX_NAME NOT LIKE 'PK_%' +ORDER BY TABLE_NAME, INDEX_NAME"); return items.Select( item => new Tuple(item.TABLE_NAME, item.INDEX_NAME, item.COLUMN_NAME, item.UNIQUE)); diff --git a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs index 00311d6af6..ca9e88fb1e 100644 --- a/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs +++ b/src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs @@ -160,6 +160,7 @@ CASE WHEN I.is_unique_constraint = 1 OR I.is_unique = 1 THEN 1 ELSE 0 END AS [U 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] inner join sys.all_columns as AC on IC.[object_id] = AC.[object_id] and IC.[column_id] = AC.[column_id] +WHERE I.name NOT LIKE 'PK_%' order by T.name, I.name"); return items.Select(item => new Tuple(item.TABLE_NAME, item.INDEX_NAME, item.COLUMN_NAME, item.UNIQUE == 1)).ToList(); diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index fb9cbad2a3..549c1378bc 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -214,6 +214,9 @@ + + + diff --git a/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs b/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs index 6964a5b8a7..dd28e559bb 100644 --- a/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs +++ b/src/Umbraco.Tests/Migrations/MigrationRunnerTests.cs @@ -18,7 +18,7 @@ namespace Umbraco.Tests.Migrations var migrations = runner.OrderedUpgradeMigrations(new List {new MultiMigration()}); - var ctx = runner.ExecuteMigrations( + var ctx = runner.InitializeMigrations( //new List {new DoRunMigration(), new DoNotRunMigration()}, migrations.ToList(), new Database("umbracoDbDSN") @@ -34,7 +34,7 @@ namespace Umbraco.Tests.Migrations var migrations = runner.OrderedUpgradeMigrations(new List { new MultiMigration() }); - var ctx = runner.ExecuteMigrations( + var ctx = runner.InitializeMigrations( //new List {new DoRunMigration(), new DoNotRunMigration()}, migrations.ToList(), new Database("umbracoDbDSN") @@ -50,7 +50,7 @@ namespace Umbraco.Tests.Migrations var migrations = runner.OrderedUpgradeMigrations(new List { new MultiMigration() }); - var ctx = runner.ExecuteMigrations( + var ctx = runner.InitializeMigrations( //new List {new DoRunMigration(), new DoNotRunMigration()}, migrations.ToList(), new Database("umbracoDbDSN") diff --git a/src/Umbraco.Web.UI/install/Default.aspx.cs b/src/Umbraco.Web.UI/install/Default.aspx.cs index 5ce92070a8..af37f0c76c 100644 --- a/src/Umbraco.Web.UI/install/Default.aspx.cs +++ b/src/Umbraco.Web.UI/install/Default.aspx.cs @@ -60,8 +60,9 @@ namespace Umbraco.Web.UI.Install _installStep = Request.GetItemAsString("installStep"); //if this is not an upgrade we will log in with the default user. - // It's not considered an upgrade if the ConfigurationStatus is missing or empty. - if (string.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false) + // It's not considered an upgrade if the ConfigurationStatus is missing or empty or if the db is not configured (initially). + if (string.IsNullOrWhiteSpace(GlobalSettings.ConfigurationStatus) == false + && (IsPostBack == false && global::Umbraco.Core.ApplicationContext.Current.DatabaseContext.IsDatabaseConfigured)) { var result = Security.ValidateCurrentUser(new HttpContextWrapper(Context));