/// <summary> /// Enumerate the nodes to be added to the upgrade path graph which create a new version of the database without a /// pre-existing version being present. /// </summary> /// <param name="databaseName">Name of the database to be upgraded.</param> /// <param name="paths">Paths of the directories containing the upgrade scripts.</param> /// <param name="insertTestData">True if test data is to be inserted along with running the upgrade scripts.</param> /// <returns>List of the nodes which create a new version of the database.</returns> private static IEnumerable <UpgradePathNode> GetCreateNodes( string databaseName, IEnumerable <string> paths, bool insertTestData) { var pattern = String.Format("{0}_*.sql", databaseName); var scriptPaths = paths.SelectMany(p => Directory.GetFiles(p, pattern)); foreach (var scriptPath in scriptPaths) { var scriptName = Path.GetFileName(scriptPath); // ReSharper disable once PossibleNullReferenceException var scriptTargetVersionString = scriptName.Substring( databaseName.Length + 1, scriptName.Length - databaseName.Length - 5); if (scriptTargetVersionString.IndexOfAny(new[] { '-', '_' }) >= 0) { continue; } var testDataScriptPath = scriptPath.Substring(0, scriptPath.Length - 4) + "_testdata.sql"; if (insertTestData && !File.Exists(testDataScriptPath)) { throw new ApplicationException(String.Format( "Missing test data insert script {0}.", Path.GetFileName(testDataScriptPath))); } DatabaseVersion scriptTargetVersion; if (!DatabaseVersion.TryParse(scriptTargetVersionString, out scriptTargetVersion)) { throw new ApplicationException(String.Format( "Database script {0} has invalid target version.", scriptPath)); } var stepGroup = new StepGroup(databaseName, scriptTargetVersion); // ReSharper disable once ObjectCreationAsStatement new RunScriptStep( stepGroup, null, scriptPath, insertTestData ? testDataScriptPath : null); var createdSchemas = new HashSet <string>( stepGroup.SchemaNames, StringComparer.InvariantCultureIgnoreCase); if (createdSchemas.Count > 0) { // ReSharper disable once ObjectCreationAsStatement new CreateSchemasStep(stepGroup, createdSchemas); } yield return(new UpgradePathNode(stepGroup)); } }
/// <summary> /// Enumerate the nodes to be added to the upgrade path graph which upgrade a specific version of the database. /// </summary> /// <param name="databaseName">Name of the database to be upgraded.</param> /// <param name="sourceVersion">Installed version of the database or null if the database is not installed. /// </param> /// <param name="existingSchemaNames">The name of the schemas associated with the previous version of the logical /// database.</param> /// <param name="paths">Paths of the directories containing the upgrade scripts.</param> /// <param name="insertTestData">True if test data is to be inserted along with running the upgrade scripts.</param> /// <returns>List of the nodes which upgrade the specified version of the database to a new version.</returns> private static IEnumerable <UpgradePathNode> GetUpgradeNodes( string databaseName, DatabaseVersion sourceVersion, IEnumerable <string> existingSchemaNames, IEnumerable <string> paths, bool insertTestData) { var pattern = String.Format("{0}_*.sql", databaseName); var scriptPaths = paths.SelectMany(p => Directory.GetFiles(p, pattern)); foreach (var scriptPath in scriptPaths) { var scriptName = Path.GetFileName(scriptPath); // ReSharper disable once PossibleNullReferenceException var versionsString = scriptName.Substring( databaseName.Length + 1, scriptName.Length - databaseName.Length - 5); if (versionsString.Contains("_")) { continue; } var index = versionsString.IndexOf('-'); if (index == -1) { continue; } var scriptSourceVersionString = versionsString.Substring(0, index); var scriptTargetVersionString = versionsString.Substring(index + 1); if (scriptTargetVersionString.Contains("-")) { continue; } if (scriptPath.ToLowerInvariant().EndsWith("_localization.sql")) { continue; } DatabaseVersion scriptSourceVersion; if (!DatabaseVersion.TryParse(scriptSourceVersionString, out scriptSourceVersion)) { throw new ApplicationException(String.Format( "Database script {0} has invalid source version.", scriptPath)); } if (scriptSourceVersion != sourceVersion) { continue; } var testDataScriptPath = scriptPath.Substring(0, scriptPath.Length - 4) + "_testdata.sql"; if (insertTestData && !File.Exists(testDataScriptPath)) { throw new ApplicationException(String.Format( "Missing test data insert script {0}.", Path.GetFileName(testDataScriptPath))); } DatabaseVersion scriptTargetVersion; if (!DatabaseVersion.TryParse(scriptTargetVersionString, out scriptTargetVersion)) { throw new ApplicationException(String.Format( "Database script {0} has invalid target version.", scriptPath)); } var stepGroup = new StepGroup(databaseName, scriptTargetVersion); // ReSharper disable once ObjectCreationAsStatement new RunScriptStep( stepGroup, sourceVersion, scriptPath, insertTestData ? testDataScriptPath : null); // ReSharper disable PossibleMultipleEnumeration var createdSchemas = new HashSet <string>( stepGroup.SchemaNames.Except(existingSchemaNames), StringComparer.InvariantCultureIgnoreCase); var deletedSchemas = new HashSet <string>( existingSchemaNames .Except(stepGroup.SchemaNames) .Except(new[] { "dbo" }), StringComparer.InvariantCultureIgnoreCase); // ReSharper restore PossibleMultipleEnumeration if (createdSchemas.Count > 0) { // ReSharper disable once ObjectCreationAsStatement new CreateSchemasStep(stepGroup, createdSchemas); } if (deletedSchemas.Count > 0) { // ReSharper disable once ObjectCreationAsStatement new DropSchemasStep(stepGroup, deletedSchemas); } yield return(new UpgradePathNode(stepGroup)); } }
/// <summary> /// Lekérdezi a metadatokat /// </summary> /// <param name="connection">Kapcsolati infó</param> /// <param name="transaction">Tranzakciópéldány</param> /// <param name="databaseName">Adatbázisnév</param> /// <param name="currentVersion">Adatbázis-változat</param> /// <param name="existingSchemaNames">A már létező sémák neve</param> private static void GetMetadata( SqlConnection connection, SqlTransaction transaction, string databaseName, out DatabaseVersion currentVersion, out HashSet <string> existingSchemaNames) { using (var command = new SqlCommand(GET_METADATA_QUERY, connection, transaction)) { command.Parameters.Add(new SqlParameter("@name", SqlDbType.NVarChar) { Value = databaseName }); var dataSet = new DataSet(); using (var adapter = new SqlDataAdapter(command)) { adapter.Fill(dataSet); } if (dataSet.Tables.Count != 2) { throw new ApplicationException("Metadata retrieval query returned unexpected number of tables."); } var versionTable = dataSet.Tables[0]; var schemaNameTable = dataSet.Tables[1]; switch (versionTable.Rows.Count) { case 0: currentVersion = null; break; case 1: var version = versionTable.Rows[0][0]; if (version == null || version == DBNull.Value) { currentVersion = null; } else { if (!(version is string) || !DatabaseVersion.TryParse((string)version, out currentVersion)) { throw new ApplicationException("The installed logical database version is invalid."); } } break; default: throw new ApplicationException("Metadata retrieval query returned multiple version numbers."); } existingSchemaNames = new HashSet <string>(StringComparer.InvariantCultureIgnoreCase); foreach (var schemaName in from DataRow schemaNameRow in schemaNameTable.Rows select schemaNameRow[0]) { if (schemaName == null || schemaName == DBNull.Value || !(schemaName is string)) { throw new ApplicationException("The installed logical database has an invalid schema name."); } existingSchemaNames.Add((string)schemaName); } } }
/// <summary> /// Create a new instance of the <see cref="UnresolvedDependency"/> class from a descriptor in an upgrade script. /// </summary> /// <param name="type">Type of the dependency.</param> /// <param name="descriptor">Descriptor from which the <see cref="UnresolvedDependency"/> should be created. /// </param> /// <param name="sourceVersion">Source version of the upgrade script the descriptor is found in.</param> /// <param name="scriptName">Name of the upgrade script.</param> /// <returns></returns> public static UnresolvedDependency FromDescriptor( DependencyType type, string descriptor, DatabaseVersion sourceVersion, string scriptName) { if (descriptor == null) { throw new ArgumentNullException("descriptor"); } if (scriptName == null) { throw new ArgumentNullException("scriptName"); } string name; DatabaseVersion minVersion; DatabaseVersion maxVersion; var index = descriptor.IndexOf('-'); if (index == -1) { if (sourceVersion == null) { throw new ApplicationException(String.Format( "Invalid dependency descriptor in {0}: {1}.", scriptName, descriptor)); } name = descriptor; minVersion = sourceVersion; maxVersion = sourceVersion; } else { name = descriptor.Substring(0, index); var versions = descriptor.Substring(index + 1); index = versions.IndexOf('-'); if (index == -1) { if (versions == "*") { minVersion = DatabaseVersion.MinValue; maxVersion = DatabaseVersion.MaxValue; } else { if (!DatabaseVersion.TryParse(versions, out minVersion)) { throw new ApplicationException(String.Format( "Invalid dependency descriptor in {0}: {1}.", scriptName, descriptor)); } maxVersion = minVersion; } } else { var minVersionString = versions.Substring(0, index); var maxVersionString = versions.Substring(index + 1); if (minVersionString == "*") { minVersion = DatabaseVersion.MinValue; } else if (!DatabaseVersion.TryParse(minVersionString, out minVersion)) { throw new ApplicationException(String.Format( "Invalid dependency descriptor in {0}: {1}.", scriptName, descriptor)); } if (maxVersionString == "*") { maxVersion = DatabaseVersion.MaxValue; } else if (!DatabaseVersion.TryParse(maxVersionString, out maxVersion)) { throw new ApplicationException(String.Format( "Invalid dependency descriptor in {0}: {1}.", scriptName, descriptor)); } } } return(new UnresolvedDependency(type, name, minVersion, maxVersion)); }
/// <summary> /// Értelmezi a parancs argumentumait /// </summary> /// <param name="option">Az opció neve</param> /// <param name="argument">Az argumentum értéke</param> /// <param name="original">A parancs szövege</param> /// <returns>Sikerült az értelmezés?</returns> protected override bool DoParseOption(string option, string argument, string original) { if (base.DoParseOption(option, argument, original)) { return(true); } switch (option) { case "databases": case "database": case "d": case "db": case "ds": case "dbs": case "logicaldatabases": case "logicaldatabase": case "ld": case "ldb": case "lds": case "ldbs": argument = ParameterHelper.Mandatory(argument, original); var databases = argument.Split(','); _databases.Clear(); foreach (var database in databases) { string name; string version; var index = database.IndexOf('-'); if (index == -1) { name = database.Trim(); version = ""; } else { name = database.Substring(0, index).Trim(); version = database.Substring(index + 1).Trim(); } if (String.IsNullOrWhiteSpace(name)) { throw new ParameterException("Logical database name cannot be empty."); } if (name.IndexOfAny(new[] { '?', '*' }) != -1) { throw new ArgumentException("Database name may not contain path wildcards."); } DatabaseVersion parsedVersion; if (String.IsNullOrWhiteSpace(version)) { parsedVersion = VersionHelper.DatabaseVersion; } else if (!DatabaseVersion.TryParse(version, out parsedVersion)) { throw new ParameterException("Invalid version number specified for logical database"); } _databases.Add(new DatabaseNameVersionPair(name, parsedVersion)); } return(true); case "paths": case "path": case "p": case "ps": case "scriptpaths": case "sqlpaths": case "scriptpath": case "sqlpath": case "sp": case "sps": case "sqlp": case "sqlps": argument = ParameterHelper.Mandatory(argument, original); var paths = argument.Split(','); _paths.Clear(); if (paths.Length == 1 && String.IsNullOrEmpty(paths[0])) { return(true); } foreach (var path in paths) { bool isAbsolute; try { isAbsolute = Path.IsPathRooted(path); } catch (ArgumentException) { throw new ParameterException("Database script path must be a valid path."); } _paths.Add(isAbsolute ? path : Path.Combine(Environment.CurrentDirectory, path)); } return(true); case "serviceuser": case "serviceusers": case "su": case "sus": case "user": case "users": case "u": case "us": argument = ParameterHelper.Mandatory(argument, original); var users = argument.Split(','); _serviceUsers.Clear(); foreach (var user in users) { if (String.IsNullOrWhiteSpace(user)) { throw new ParameterException("Service user name cannot be empty."); } _serviceUsers.Add(user.Trim()); } return(true); case "testdata": case "t": case "td": case "test": case "inserttestdata": case "it": case "itd": argument = ParameterHelper.Mandatory(argument, original).Trim(); switch (argument.ToLower()) { case "0": case "no": case "false": _insertTestData = false; break; case "1": case "yes": case "true": _insertTestData = true; break; default: throw new ParameterException(String.Format( "Option {0} requires a boolean argument.", original)); } return(true); default: throw new ParameterException(String.Format( "Unknown option {0} for command {1}.", original, Original)); } }