Skip to content

Commit

Permalink
Merge branch 'main' into release/6.0.0
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/Tests/ApprovalFiles/NoPublicApiChanges.Run.Net.verified.cs
  • Loading branch information
droyad committed Dec 17, 2024
2 parents f0ac9b7 + ff15148 commit c77ddde
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 7 deletions.
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/)
Expand All @@ -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.
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;

```
6 changes: 6 additions & 0 deletions src/Sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/Sample/README.md
Original file line number Diff line number Diff line change
@@ -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
6 changes: 3 additions & 3 deletions src/Sample/appsettings.json
Original file line number Diff line number Diff line change
@@ -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;"
}
}
15 changes: 15 additions & 0 deletions src/Sample/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
129 changes: 127 additions & 2 deletions src/dbup-firebird/FirebirdExtensions.cs
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -49,4 +54,124 @@ public static UpgradeEngineBuilder FirebirdDatabase(IConnectionManager connectio
builder.WithPreprocessor(new FirebirdPreprocessor());
return builder;
}
}


//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;

/// <summary>
/// Ensures that the database specified in the connection string exists.
/// </summary>
/// <param name="supported">Fluent helper type.</param>
/// <param name="connectionString">The connection string.</param>
/// <param name="logger">The <see cref="DbUp.Engine.Output.IUpgradeLog"/> used to record actions.</param>
/// <returns></returns>
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;
}
}
}

/// <summary>
/// Drop the database specified in the connection string.
/// </summary>
/// <param name="supported">Fluent helper type.</param>
/// <param name="connectionString">The connection string.</param>
/// <param name="logger">The <see cref="DbUp.Engine.Output.IUpgradeLog"/> used to record actions.</param>
/// <returns></returns>
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;
}
}
}

}

0 comments on commit c77ddde

Please sign in to comment.