diff --git a/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.cs b/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.cs
index 00d5ce0..d7c8f73 100644
--- a/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.cs
+++ b/src/Tests/ApprovalFiles/NoPublicApiChanges.Run.approved.cs
@@ -13,11 +13,17 @@ public static DbUp.Builder.UpgradeEngineBuilder PostgresqlDatabase(this DbUp.Bui
public static DbUp.Builder.UpgradeEngineBuilder PostgresqlDatabase(this DbUp.Builder.SupportedDatabases supported, string connectionString, string schema, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { }
public static DbUp.Builder.UpgradeEngineBuilder PostgresqlDatabase(this DbUp.Builder.SupportedDatabases supported, string connectionString, string schema, DbUp.Postgresql.PostgresqlConnectionOptions connectionOptions) { }
public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForEnsureDatabase supported, string connectionString) { }
+ public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForDropDatabase supported, string connectionString) { }
public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForEnsureDatabase supported, string connectionString, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { }
public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForEnsureDatabase supported, string connectionString, DbUp.Postgresql.PostgresqlConnectionOptions connectionOptions) { }
public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForEnsureDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger) { }
+ public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForDropDatabase supported, string connectionString, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { }
+ public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForDropDatabase supported, string connectionString, DbUp.Postgresql.PostgresqlConnectionOptions connectionOptions) { }
+ public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForDropDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger) { }
public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForEnsureDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { }
public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForEnsureDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger, DbUp.Postgresql.PostgresqlConnectionOptions connectionOptions) { }
+ public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForDropDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger, System.Security.Cryptography.X509Certificates.X509Certificate2 certificate) { }
+ public static void PostgresqlDatabase(this DbUp.SupportedDatabasesForDropDatabase supported, string connectionString, DbUp.Engine.Output.IUpgradeLog logger, DbUp.Postgresql.PostgresqlConnectionOptions connectionOptions) { }
}
namespace DbUp.Postgresql
{
diff --git a/src/dbup-postgresql/PostgresqlExtensions.cs b/src/dbup-postgresql/PostgresqlExtensions.cs
index f6ed796..921df87 100644
--- a/src/dbup-postgresql/PostgresqlExtensions.cs
+++ b/src/dbup-postgresql/PostgresqlExtensions.cs
@@ -230,6 +230,164 @@ PostgresqlConnectionOptions connectionOptions
logger.LogInformation(@"Created database {0}", databaseName);
}
+ ///
+ /// Drops the database specified in the connection string if it exists.
+ ///
+ /// Fluent helper type.
+ /// The connection string.
+ ///
+ public static void PostgresqlDatabase(this SupportedDatabasesForDropDatabase supported, string connectionString)
+ {
+ PostgresqlDatabase(supported, connectionString, new ConsoleUpgradeLog());
+ }
+
+ ///
+ /// Drops the database specified in the connection string if it exists using SSL for the connection.
+ ///
+ /// Fluent helper type.
+ /// The connection string.
+ /// Certificate for securing connection.
+ ///
+ public static void PostgresqlDatabase(this SupportedDatabasesForDropDatabase supported, string connectionString, X509Certificate2 certificate)
+ {
+ PostgresqlDatabase(supported, connectionString, new ConsoleUpgradeLog(), certificate);
+ }
+
+ ///
+ /// Drops the database specified in the connection string if it exists using SSL for the connection.
+ ///
+ /// Fluent helper type.
+ /// The connection string.
+ /// Connection SSL to customize SSL behaviour
+ ///
+ public static void PostgresqlDatabase(this SupportedDatabasesForDropDatabase supported, string connectionString, PostgresqlConnectionOptions connectionOptions)
+ {
+ PostgresqlDatabase(supported, connectionString, new ConsoleUpgradeLog(), connectionOptions);
+ }
+
+ ///
+ /// Drops that the database specified in the connection string if it exists.
+ ///
+ /// Fluent helper type.
+ /// The connection string.
+ /// The used to record actions.
+ ///
+ public static void PostgresqlDatabase(this SupportedDatabasesForDropDatabase supported, string connectionString, IUpgradeLog logger)
+ {
+ PostgresqlDatabase(supported, connectionString, logger, new PostgresqlConnectionOptions());
+ }
+
+ public static void PostgresqlDatabase(this SupportedDatabasesForDropDatabase supported, string connectionString, IUpgradeLog logger, X509Certificate2 certificate)
+ {
+ var options = new PostgresqlConnectionOptions
+ {
+ ClientCertificate = certificate
+ };
+ PostgresqlDatabase(supported, connectionString, logger, options);
+ }
+
+ public static void PostgresqlDatabase(
+ this SupportedDatabasesForDropDatabase supported,
+ string connectionString,
+ IUpgradeLog logger,
+ PostgresqlConnectionOptions connectionOptions
+ )
+ {
+ if (supported == null) throw new ArgumentNullException("supported");
+
+ if (string.IsNullOrEmpty(connectionString) || connectionString.Trim() == string.Empty)
+ {
+ throw new ArgumentNullException("connectionString");
+ }
+
+ if (logger == null) throw new ArgumentNullException("logger");
+
+ var masterConnectionStringBuilder = new NpgsqlConnectionStringBuilder(connectionString);
+
+ var databaseName = masterConnectionStringBuilder.Database;
+
+ if (string.IsNullOrEmpty(databaseName) || databaseName.Trim() == string.Empty)
+ {
+ throw new InvalidOperationException("The connection string does not specify a database name.");
+ }
+
+ if (databaseName == connectionOptions.MasterDatabaseName)
+ {
+ throw new InvalidOperationException("Database in connection string needs to be different than the master database in PostgresqlConnectionOptions.");
+ }
+
+ masterConnectionStringBuilder.Database = connectionOptions.MasterDatabaseName;
+ masterConnectionStringBuilder.SearchPath = "public";
+
+ var logMasterConnectionStringBuilder = new NpgsqlConnectionStringBuilder(masterConnectionStringBuilder.ConnectionString);
+ if (!string.IsNullOrEmpty(logMasterConnectionStringBuilder.Password))
+ {
+ logMasterConnectionStringBuilder.Password = "******";
+ }
+
+ logger.LogDebug("Master ConnectionString => {0}", logMasterConnectionStringBuilder.ConnectionString);
+
+ var factory = new DataSourceConnectionFactory(masterConnectionStringBuilder.ConnectionString, connectionOptions);
+ using var connection = factory.CreateConnection();
+ connection.Open();
+
+ var sqlCommandText =
+ $@"SELECT case WHEN oid IS NOT NULL THEN 1 ELSE 0 end FROM pg_database WHERE datname = '{databaseName}' limit 1;";
+
+ // check to see if the database already exists..
+ using (var command = new NpgsqlCommand(sqlCommandText, connection)
+ {
+ CommandType = CommandType.Text
+ })
+ {
+ var results = Convert.ToInt32(command.ExecuteScalar());
+
+ // if the database does not exist, we're done here...
+ if (results == 0)
+ {
+ logger.LogInformation(@"Database {0} does not exist. Skipping delete operation.", databaseName);
+ return;
+ }
+ }
+
+ // prevent new connections to the database
+ sqlCommandText = $"alter database \"{databaseName}\" with ALLOW_CONNECTIONS false;";
+ using (var command = new NpgsqlCommand(sqlCommandText, connection)
+ {
+ CommandType = CommandType.Text
+ })
+ {
+ command.ExecuteNonQuery();
+ }
+
+ logger.LogInformation(@"Stopped connections for database {0}.", databaseName);
+
+ // terminate all existing connections to the database
+ sqlCommandText = $"select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where pg_stat_activity.datname = \'{databaseName}\';";
+ using (var command = new NpgsqlCommand(sqlCommandText, connection)
+ {
+ CommandType = CommandType.Text
+ })
+ {
+ command.ExecuteNonQuery();
+ }
+
+ logger.LogInformation(@"Closed existing connections for database {0}.", databaseName);
+
+ sqlCommandText = $"drop database \"{databaseName}\";";
+
+ // drop the database
+ using (var command = new NpgsqlCommand(sqlCommandText, connection)
+ {
+ CommandType = CommandType.Text
+ })
+ {
+ command.ExecuteNonQuery();
+ }
+
+ logger.LogInformation(@"Dropped database {0}.", databaseName);
+ }
+
///
/// Tracks the list of executed scripts in a PostgreSQL table.
///