@@ -245,6 +245,164 @@ PostgresqlConnectionOptions connectionOptions
245245 logger . LogInformation ( @"Created database {0}" , databaseName ) ;
246246 }
247247
248+ /// <summary>
249+ /// Drops the database specified in the connection string if it exists.
250+ /// </summary>
251+ /// <param name="supported">Fluent helper type.</param>
252+ /// <param name="connectionString">The connection string.</param>
253+ /// <returns></returns>
254+ public static void PostgresqlDatabase ( this SupportedDatabasesForDropDatabase supported , string connectionString )
255+ {
256+ PostgresqlDatabase ( supported , connectionString , new ConsoleUpgradeLog ( ) ) ;
257+ }
258+
259+ /// <summary>
260+ /// Drops the database specified in the connection string if it exists using SSL for the connection.
261+ /// </summary>
262+ /// <param name="supported">Fluent helper type.</param>
263+ /// <param name="connectionString">The connection string.</param>
264+ /// <param name="certificate">Certificate for securing connection.</param>
265+ /// <returns></returns>
266+ public static void PostgresqlDatabase ( this SupportedDatabasesForDropDatabase supported , string connectionString , X509Certificate2 certificate )
267+ {
268+ PostgresqlDatabase ( supported , connectionString , new ConsoleUpgradeLog ( ) , certificate ) ;
269+ }
270+
271+ /// <summary>
272+ /// Drops the database specified in the connection string if it exists using SSL for the connection.
273+ /// </summary>
274+ /// <param name="supported">Fluent helper type.</param>
275+ /// <param name="connectionString">The connection string.</param>
276+ /// <param name="connectionOptions">Connection SSL to customize SSL behaviour</param>
277+ /// <returns></returns>
278+ public static void PostgresqlDatabase ( this SupportedDatabasesForDropDatabase supported , string connectionString , PostgresqlConnectionOptions connectionOptions )
279+ {
280+ PostgresqlDatabase ( supported , connectionString , new ConsoleUpgradeLog ( ) , connectionOptions ) ;
281+ }
282+
283+ /// <summary>
284+ /// Drops that the database specified in the connection string if it exists.
285+ /// </summary>
286+ /// <param name="supported">Fluent helper type.</param>
287+ /// <param name="connectionString">The connection string.</param>
288+ /// <param name="logger">The <see cref="DbUp.Engine.Output.IUpgradeLog"/> used to record actions.</param>
289+ /// <returns></returns>
290+ public static void PostgresqlDatabase ( this SupportedDatabasesForDropDatabase supported , string connectionString , IUpgradeLog logger )
291+ {
292+ PostgresqlDatabase ( supported , connectionString , logger , new PostgresqlConnectionOptions ( ) ) ;
293+ }
294+
295+ public static void PostgresqlDatabase ( this SupportedDatabasesForDropDatabase supported , string connectionString , IUpgradeLog logger , X509Certificate2 certificate )
296+ {
297+ var options = new PostgresqlConnectionOptions
298+ {
299+ ClientCertificate = certificate
300+ } ;
301+ PostgresqlDatabase ( supported , connectionString , logger , options ) ;
302+ }
303+
304+ public static void PostgresqlDatabase (
305+ this SupportedDatabasesForDropDatabase supported ,
306+ string connectionString ,
307+ IUpgradeLog logger ,
308+ PostgresqlConnectionOptions connectionOptions
309+ )
310+ {
311+ if ( supported == null ) throw new ArgumentNullException ( "supported" ) ;
312+
313+ if ( string . IsNullOrEmpty ( connectionString ) || connectionString . Trim ( ) == string . Empty )
314+ {
315+ throw new ArgumentNullException ( "connectionString" ) ;
316+ }
317+
318+ if ( logger == null ) throw new ArgumentNullException ( "logger" ) ;
319+
320+ var masterConnectionStringBuilder = new NpgsqlConnectionStringBuilder ( connectionString ) ;
321+
322+ var databaseName = masterConnectionStringBuilder . Database ;
323+
324+ if ( string . IsNullOrEmpty ( databaseName ) || databaseName . Trim ( ) == string . Empty )
325+ {
326+ throw new InvalidOperationException ( "The connection string does not specify a database name." ) ;
327+ }
328+
329+ if ( databaseName == connectionOptions . MasterDatabaseName )
330+ {
331+ throw new InvalidOperationException ( "Database in connection string needs to be different than the master database in PostgresqlConnectionOptions." ) ;
332+ }
333+
334+ masterConnectionStringBuilder . Database = connectionOptions . MasterDatabaseName ;
335+ masterConnectionStringBuilder . SearchPath = "public" ;
336+
337+ var logMasterConnectionStringBuilder = new NpgsqlConnectionStringBuilder ( masterConnectionStringBuilder . ConnectionString ) ;
338+ if ( ! string . IsNullOrEmpty ( logMasterConnectionStringBuilder . Password ) )
339+ {
340+ logMasterConnectionStringBuilder . Password = "******" ;
341+ }
342+
343+ logger . LogDebug ( "Master ConnectionString => {0}" , logMasterConnectionStringBuilder . ConnectionString ) ;
344+
345+ var factory = new DataSourceConnectionFactory ( masterConnectionStringBuilder . ConnectionString , connectionOptions ) ;
346+ using var connection = factory . CreateConnection ( ) ;
347+ connection . Open ( ) ;
348+
349+ var sqlCommandText =
350+ $@ "SELECT case WHEN oid IS NOT NULL THEN 1 ELSE 0 end FROM pg_database WHERE datname = '{ databaseName } ' limit 1;";
351+
352+ // check to see if the database already exists..
353+ using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
354+ {
355+ CommandType = CommandType . Text
356+ } )
357+ {
358+ var results = Convert . ToInt32 ( command . ExecuteScalar ( ) ) ;
359+
360+ // if the database does not exist, we're done here...
361+ if ( results == 0 )
362+ {
363+ logger . LogInformation ( @"Database {0} does not exist. Skipping delete operation." , databaseName ) ;
364+ return ;
365+ }
366+ }
367+
368+ // prevent new connections to the database
369+ sqlCommandText = $ "alter database \" { databaseName } \" with ALLOW_CONNECTIONS false;";
370+ using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
371+ {
372+ CommandType = CommandType . Text
373+ } )
374+ {
375+ command . ExecuteNonQuery ( ) ;
376+ }
377+
378+ logger . LogInformation ( @"Stopped connections for database {0}." , databaseName ) ;
379+
380+ // terminate all existing connections to the database
381+ sqlCommandText = $ "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where pg_stat_activity.datname = \' { databaseName } \' ;";
382+ using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
383+ {
384+ CommandType = CommandType . Text
385+ } )
386+ {
387+ command . ExecuteNonQuery ( ) ;
388+ }
389+
390+ logger . LogInformation ( @"Closed existing connections for database {0}." , databaseName ) ;
391+
392+ sqlCommandText = $ "drop database \" { databaseName } \" ;";
393+
394+ // drop the database
395+ using ( var command = new NpgsqlCommand ( sqlCommandText , connection )
396+ {
397+ CommandType = CommandType . Text
398+ } )
399+ {
400+ command . ExecuteNonQuery ( ) ;
401+ }
402+
403+ logger . LogInformation ( @"Dropped database {0}." , databaseName ) ;
404+ }
405+
248406 /// <summary>
249407 /// Tracks the list of executed scripts in a PostgreSQL table.
250408 /// </summary>
0 commit comments