diff --git a/src/Sample/Program.cs b/src/Sample/Program.cs index 9bcb7ee..dcb759f 100644 --- a/src/Sample/Program.cs +++ b/src/Sample/Program.cs @@ -13,6 +13,12 @@ static int Main() var config = GetConfig(); string connectionString = config.GetConnectionString("SampleFirebird"); + // If you used `docker compose up` for creating a server and a database, the database already exists. + // You can see that a new database can be created using EnsureDatabase.For.FirebirdDatabase(connectionString) by changing the Database parameter (the fdb filename) + // in the connectionString in appsettings.json + // You can also try to drop a database by using DropDatabase.For.FirebirdDatabase(connectionString); + EnsureDatabase.For.FirebirdDatabase(connectionString); + var upgrader = DeployChanges.To .FirebirdDatabase(connectionString) diff --git a/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.DotNet.verified.cs b/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.DotNet.verified.cs index 797159c..d9d6dfa 100644 --- a/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.DotNet.verified.cs +++ b/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.DotNet.verified.cs @@ -6,6 +6,8 @@ public static class FirebirdExtensions public static DbUp.Builder.UpgradeEngineBuilder FirebirdDatabase(DbUp.Engine.Transactions.IConnectionManager connectionManager) { } public static DbUp.Builder.UpgradeEngineBuilder FirebirdDatabase(this DbUp.Builder.SupportedDatabases supported, string connectionString) { } public static DbUp.Builder.UpgradeEngineBuilder FirebirdDatabase(this DbUp.Builder.SupportedDatabases supported, DbUp.Engine.Transactions.IConnectionManager connectionManager) { } + public static void FirebirdDatabase(this DbUp.SupportedDatabasesForEnsureDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger = null) { } + public static void FirebirdDatabase(this DbUp.SupportedDatabasesForDropDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger = null) { } } namespace DbUp.Firebird { diff --git a/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.Net.verified.cs b/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.Net.verified.cs index 797159c..d9d6dfa 100644 --- a/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.Net.verified.cs +++ b/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.Net.verified.cs @@ -6,6 +6,8 @@ public static class FirebirdExtensions public static DbUp.Builder.UpgradeEngineBuilder FirebirdDatabase(DbUp.Engine.Transactions.IConnectionManager connectionManager) { } public static DbUp.Builder.UpgradeEngineBuilder FirebirdDatabase(this DbUp.Builder.SupportedDatabases supported, string connectionString) { } public static DbUp.Builder.UpgradeEngineBuilder FirebirdDatabase(this DbUp.Builder.SupportedDatabases supported, DbUp.Engine.Transactions.IConnectionManager connectionManager) { } + public static void FirebirdDatabase(this DbUp.SupportedDatabasesForEnsureDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger = null) { } + public static void FirebirdDatabase(this DbUp.SupportedDatabasesForDropDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger = null) { } } namespace DbUp.Firebird { diff --git a/src/dbup-firebird/FirebirdExtensions.cs b/src/dbup-firebird/FirebirdExtensions.cs index 60481e5..35be25e 100644 --- a/src/dbup-firebird/FirebirdExtensions.cs +++ b/src/dbup-firebird/FirebirdExtensions.cs @@ -1,6 +1,11 @@ -using DbUp.Builder; +using System; +using System.IO; +using DbUp; +using DbUp.Builder; +using DbUp.Engine.Output; using DbUp.Engine.Transactions; using DbUp.Firebird; +using FirebirdSql.Data.FirebirdClient; // ReSharper disable once CheckNamespace @@ -49,4 +54,124 @@ public static UpgradeEngineBuilder FirebirdDatabase(IConnectionManager connectio builder.WithPreprocessor(new FirebirdPreprocessor()); return builder; } -} \ No newline at end of file + + + //The code below concerning EnsureDatabase and DropDatabase is a modified version from a PR from Github user @hhindriks. Thank you for your contribution. + + //Error codes from Firebird (see https://www.firebirdsql.org/pdfrefdocs/Firebird-2.1-ErrorCodes.pdf) + const int FbIoError = 335544344; + const int FbNetworkError = 335544721; + const int FbLockTimeout = 335544510; + + /// + /// Ensures that the database specified in the connection string exists. + /// + /// Fluent helper type. + /// The connection string. + /// The used to record actions. + /// + public static void FirebirdDatabase(this SupportedDatabasesForEnsureDatabase supported, string connectionString, IUpgradeLog logger = null) + { + logger ??= new ConsoleUpgradeLog(); + var builder = new FbConnectionStringBuilder(connectionString); + + if (builder.ServerType == FbServerType.Embedded) + { + //The code for the embedded servertype is currently not tested. + //Comes from the original PR from @hhindriks + if (!File.Exists(builder.Database)) + { + FbConnection.CreateDatabase(builder.ToString()); + logger.WriteInformation("Created database {0}", builder.Database); + } + else + { + logger.WriteInformation("Database {0} already exists", builder.Database); + } + } + else + { + using var conn = new FbConnection(builder.ToString()); + try + { + conn.Open(); + conn.Close(); + logger.WriteInformation("Database {0} already exists", builder.Database); + } + catch (FbException ex) when (ex.ErrorCode == FbIoError) + { + FbConnection.CreateDatabase(builder.ToString()); + logger.WriteInformation("Created database {0}", builder.Database); + } + catch (FbException ex) when (ex.ErrorCode == FbNetworkError) + { + logger.WriteError("Could not access server. The server: {0} is probably not started.", builder.DataSource); + throw; + } + catch (FbException) + { + logger.WriteError("Ensure Database: Unknown firebird error when trying to access the server: {0}.", builder.DataSource); + throw; + } + catch (Exception) + { + logger.WriteError("Ensure Database: Unknown error when trying to access the server: {0}.", builder.DataSource); + throw; + } + } + } + + /// + /// Drop the database specified in the connection string. + /// + /// Fluent helper type. + /// The connection string. + /// The used to record actions. + /// + public static void FirebirdDatabase(this SupportedDatabasesForDropDatabase supported, string connectionString, IUpgradeLog logger = null) + { + logger ??= new ConsoleUpgradeLog(); + var builder = new FbConnectionStringBuilder(connectionString); + + if (builder.ServerType == FbServerType.Embedded) + { + //The code for the embedded servertype is currently not tested. + //Comes from the original PR from @hhindriks + if (File.Exists(builder.Database)) + { + FbConnection.DropDatabase(builder.ToString()); + logger.WriteInformation("Dropped database {0}", builder.Database); + } + } + else + { + try + { + //There seems to be an error in the FirebirdClient when trying to drop a database that does not exist. + //It gives a NullRefException instead of the expected FbException. + FbConnection.DropDatabase(builder.ToString()); + logger.WriteInformation("Dropped database {0}", builder.Database); + } + catch (FbException ex) when (ex.ErrorCode == FbIoError) + { + logger.WriteWarning("Nothing to Drop. No database found."); + } + catch (FbException ex) when (ex.ErrorCode == FbLockTimeout) + { + logger.WriteError("Can't drop database. Are there still an active connection?"); + throw; + } + catch (FbException) + { + logger.WriteError("Drop Database: Unknown firebird error when trying to access the server: {0}.", builder.DataSource); + throw; + } + catch (Exception) + { + logger.WriteError("Drop Database: Unknown error when trying to access the server: {0}.", builder.DataSource); + throw; + } + } + } + +}