diff --git a/README.md b/README.md
index 3c5302a..6957636 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,8 @@
[![Prerelease](https://img.shields.io/nuget/vpre/dbup-firebird?color=orange&label=prerelease)](https://www.nuget.org/packages/dbup-firebird)
# DbUp Firebird support
-DbUp is a .NET library that helps you to deploy changes to SQL Server databases. It tracks which SQL scripts have been run already, and runs the change scripts that are needed to get your database up to date.
+DbUp is a .NET library that helps you to deploy changes to relational databases. It tracks which SQL scripts have been run already, and runs the change scripts that are needed to get your database up to date.
+This Provider is for deploying to Firebird databases.
## Getting Help
To learn more about DbUp check out the [documentation](https://dbup.readthedocs.io/en/latest/)
@@ -13,4 +14,24 @@ Please only log issue related to Firebird support in this repo. For cross cuttin
# Contributing
-See the [readme in our main repo](https://github.com/DbUp/DbUp/blob/master/README.md) for how to get started and contribute.
\ No newline at end of file
+See the [readme in our main repo](https://github.com/DbUp/DbUp/blob/master/README.md) for how to get started and contribute.
+
+# Quirks concerning the Firebird implementation
+
+The Journal Table for Firebird is called `"schemaversions"` i.e. with quotes. This can be confusing since other providers do not use quotes.
+
+It will not be fixed because of backwards compatibility. You can check the content of the table by using
+
+```sql
+select * from "schemaversions"
+```
+
+In a new project you can also choose another name for the JournalTable instead like this:
+
+```csharp
+ public static UpgradeEngineBuilder JournalToFirebirdTable(this UpgradeEngineBuilder builder)
+ {
+ builder.Configure(c => c.Journal = new FirebirdTableJournal(() => c.ConnectionManager, () => c.Log, "ABetterTableName"));
+ return builder;
+
+```
\ No newline at end of file
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/Sample/README.md b/src/Sample/README.md
new file mode 100644
index 0000000..454585d
--- /dev/null
+++ b/src/Sample/README.md
@@ -0,0 +1,5 @@
+To try this sample that demonstrates the use of DbUp for Firebird you can install docker and run `docker compose up` from a terminal in this folder.
+
+After that you can run the sample project and notice the scripts are run against the fbsample.fdb database
+
+The Firebird server uses the latest jacobalberty/firebird image from Dockerhub. At the time of writing the latest image uses the v4.0.1 version of the firebird server
diff --git a/src/Sample/appsettings.json b/src/Sample/appsettings.json
index b40a501..a2f2ff4 100644
--- a/src/Sample/appsettings.json
+++ b/src/Sample/appsettings.json
@@ -1,5 +1,5 @@
{
- "ConnectionStrings": {
- "SampleFirebird": "User=SOMEUSER;Password=SOMEPWD;Database=c:\\somedb.fdb;DataSource=SOMESERVERNAME;Port=SOMEPORT;Dialect=3;Charset=ISO8859_1;ServerType=0;Connection lifetime=15;Pooling=true;MinPoolSize=0;MaxPoolSize=50;"
- }
+ "ConnectionStrings": {
+ "SampleFirebird": "User=SYSDBA;Password=firebirdsample;Database=/firebird/data/fbsample.fdb;DataSource=localhost;Port=3050;Dialect=3;Charset=ISO8859_1;ServerType=0;Connection lifetime=15;Pooling=true;MinPoolSize=0;MaxPoolSize=50;"
+ }
}
\ No newline at end of file
diff --git a/src/Sample/docker-compose.yml b/src/Sample/docker-compose.yml
new file mode 100644
index 0000000..8bae4ad
--- /dev/null
+++ b/src/Sample/docker-compose.yml
@@ -0,0 +1,15 @@
+services:
+ firebird:
+ image: jacobalberty/firebird
+ container_name: dbupfirebird
+ hostname: firebird
+ environment:
+ - ISC_USER=SYSDBA
+ - ISC_PASSWORD=firebirdsample
+ - FIREBIRD_DATABASE=fbsample.fdb
+ - FIREBIRD_USER=sampleuser
+ - FIREBIRD_PASSWORD=firebirdsample
+ ports:
+ - 3050:3050
+ volumes:
+ - ./firebird/intl/:/firebird/intl
diff --git a/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.cs b/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.cs
index 797159c..d9d6dfa 100644
--- a/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.cs
+++ b/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.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..62d301c 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.LogInformation("Created database {0}", builder.Database);
+ }
+ else
+ {
+ logger.LogInformation("Database {0} already exists", builder.Database);
+ }
+ }
+ else
+ {
+ using var conn = new FbConnection(builder.ToString());
+ try
+ {
+ conn.Open();
+ conn.Close();
+ logger.LogInformation("Database {0} already exists", builder.Database);
+ }
+ catch (FbException ex) when (ex.ErrorCode == FbIoError)
+ {
+ FbConnection.CreateDatabase(builder.ToString());
+ logger.LogInformation("Created database {0}", builder.Database);
+ }
+ catch (FbException ex) when (ex.ErrorCode == FbNetworkError)
+ {
+ logger.LogError("Could not access server. The server: {0} is probably not started.", builder.DataSource);
+ throw;
+ }
+ catch (FbException)
+ {
+ logger.LogError("Ensure Database: Unknown firebird error when trying to access the server: {0}.", builder.DataSource);
+ throw;
+ }
+ catch (Exception)
+ {
+ logger.LogError("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.LogInformation("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.LogInformation("Dropped database {0}", builder.Database);
+ }
+ catch (FbException ex) when (ex.ErrorCode == FbIoError)
+ {
+ logger.LogWarning("Nothing to Drop. No database found.");
+ }
+ catch (FbException ex) when (ex.ErrorCode == FbLockTimeout)
+ {
+ logger.LogError("Can't drop database. Are there still an active connection?");
+ throw;
+ }
+ catch (FbException)
+ {
+ logger.LogError("Drop Database: Unknown firebird error when trying to access the server: {0}.", builder.DataSource);
+ throw;
+ }
+ catch (Exception)
+ {
+ logger.LogError("Drop Database: Unknown error when trying to access the server: {0}.", builder.DataSource);
+ throw;
+ }
+ }
+ }
+
+}