From 6c024a4a37ef23d06060a9c186dd970f6427fed6 Mon Sep 17 00:00:00 2001 From: p4cket Date: Sat, 5 Dec 2020 14:42:37 -0500 Subject: [PATCH 1/9] test --- postgresql/resource_postgresql_database.go | 21 +++++++++++++++++++++ postgresql/resource_postgresql_grant.go | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/postgresql/resource_postgresql_database.go b/postgresql/resource_postgresql_database.go index a61c1178..51e62617 100644 --- a/postgresql/resource_postgresql_database.go +++ b/postgresql/resource_postgresql_database.go @@ -263,6 +263,18 @@ func resourcePostgreSQLDatabaseDelete(d *schema.ResourceData, meta interface{}) return err } + //block new connections to database + if c.featureSupported(featureDBAllowConnections) { + if err := setDBAllowConns(c, d); err != nil { + return fmt.Errorf("Error updating database AllowConnections during DROP DATABASE: %w", err) + } + } + + //terminate all connections to database + if err := terminateBConnections(c, dbName); err != nil { + return err + } + sql := fmt.Sprintf("DROP DATABASE %s", pq.QuoteIdentifier(dbName)) if _, err := c.DB().Exec(sql); err != nil { return fmt.Errorf("Error dropping database: %w", err) @@ -548,3 +560,12 @@ func doSetDBIsTemplate(c *Client, dbName string, isTemplate bool) error { return nil } + +func terminateBConnections(c *Client, dbName string) error { + sql := fmt.Sprintf("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname '%s' AND pid <> pg_backend_pid();", pq.QuoteIdentifier(dbName)) + if _, err := c.DB().Exec(sql); err != nil { + return fmt.Errorf("Error updating database IS_TEMPLATE: %w", err) + } + + return nil +} diff --git a/postgresql/resource_postgresql_grant.go b/postgresql/resource_postgresql_grant.go index c60b28da..6203880a 100644 --- a/postgresql/resource_postgresql_grant.go +++ b/postgresql/resource_postgresql_grant.go @@ -257,13 +257,13 @@ JOIN pg_namespace ON pg_namespace.oid = pg_proc.pronamespace LEFT JOIN ( select acls.* from ( - SELECT proname, pronamespace, (aclexplode(proacl)).* FROM pg_proc + SELECT proname, prokind, pronamespace, (aclexplode(proacl)).* FROM pg_proc ) acls JOIN pg_roles on grantee = pg_roles.oid WHERE rolname = $1 ) privs -USING (proname, pronamespace) - WHERE nspname = $2 +USING (proname, pronamespace, relkind) + WHERE nspname = $2 AND relkind = $3 GROUP BY pg_proc.proname ` default: From 723c56f9589971f4360a69f5dbbb91dca5b81702 Mon Sep 17 00:00:00 2001 From: p4cket Date: Sun, 6 Dec 2020 13:28:45 -0500 Subject: [PATCH 2/9] testing --- postgresql/resource_postgresql_database.go | 26 ++++++++++++---------- postgresql/resource_postgresql_grant.go | 6 ++--- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/postgresql/resource_postgresql_database.go b/postgresql/resource_postgresql_database.go index 51e62617..363ec203 100644 --- a/postgresql/resource_postgresql_database.go +++ b/postgresql/resource_postgresql_database.go @@ -263,14 +263,7 @@ func resourcePostgreSQLDatabaseDelete(d *schema.ResourceData, meta interface{}) return err } - //block new connections to database - if c.featureSupported(featureDBAllowConnections) { - if err := setDBAllowConns(c, d); err != nil { - return fmt.Errorf("Error updating database AllowConnections during DROP DATABASE: %w", err) - } - } - - //terminate all connections to database + // Terminate all active connections and block new one if err := terminateBConnections(c, dbName); err != nil { return err } @@ -562,10 +555,19 @@ func doSetDBIsTemplate(c *Client, dbName string, isTemplate bool) error { } func terminateBConnections(c *Client, dbName string) error { - sql := fmt.Sprintf("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname '%s' AND pid <> pg_backend_pid();", pq.QuoteIdentifier(dbName)) - if _, err := c.DB().Exec(sql); err != nil { - return fmt.Errorf("Error updating database IS_TEMPLATE: %w", err) + if c.featureSupported(featureDBAllowConnections) { + alterSql := fmt.Sprintf("ALTER DATABASE %s ALLOW_CONNECTIONS false", pq.QuoteIdentifier(dbName)) + + if _, err := c.DB().Exec(alterSql); err != nil { + return fmt.Errorf("Error blocking connections to database: %w", err) + } + } + + terminateSql := fmt.Sprintf("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '%s' AND pid <> pg_backend_pid()", dbName) + + if _, err := c.DB().Exec(terminateSql); err != nil { + return fmt.Errorf("Error terminating database connections: %w", err) } return nil -} +} \ No newline at end of file diff --git a/postgresql/resource_postgresql_grant.go b/postgresql/resource_postgresql_grant.go index 6203880a..66becbbc 100644 --- a/postgresql/resource_postgresql_grant.go +++ b/postgresql/resource_postgresql_grant.go @@ -257,13 +257,13 @@ JOIN pg_namespace ON pg_namespace.oid = pg_proc.pronamespace LEFT JOIN ( select acls.* from ( - SELECT proname, prokind, pronamespace, (aclexplode(proacl)).* FROM pg_proc + SELECT proname, pronamespace, (aclexplode(proacl)).* FROM pg_proc ) acls JOIN pg_roles on grantee = pg_roles.oid WHERE rolname = $1 ) privs -USING (proname, pronamespace, relkind) - WHERE nspname = $2 AND relkind = $3 +USING (proname, pronamespace) + WHERE nspname = $2 GROUP BY pg_proc.proname ` default: From f066d57e643f0cfe9572ac8121cad51ecf035e96 Mon Sep 17 00:00:00 2001 From: p4cket Date: Sun, 6 Dec 2020 13:29:10 -0500 Subject: [PATCH 3/9] testing --- postgresql/resource_postgresql_grant.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgresql/resource_postgresql_grant.go b/postgresql/resource_postgresql_grant.go index 66becbbc..c60b28da 100644 --- a/postgresql/resource_postgresql_grant.go +++ b/postgresql/resource_postgresql_grant.go @@ -263,7 +263,7 @@ LEFT JOIN ( WHERE rolname = $1 ) privs USING (proname, pronamespace) - WHERE nspname = $2 + WHERE nspname = $2 GROUP BY pg_proc.proname ` default: From 0ed73b5693d525b973fcac93cc2c3caa3a837e31 Mon Sep 17 00:00:00 2001 From: p4cket Date: Sun, 6 Dec 2020 13:29:32 -0500 Subject: [PATCH 4/9] testing --- postgresql/resource_postgresql_database.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgresql/resource_postgresql_database.go b/postgresql/resource_postgresql_database.go index 363ec203..743508d8 100644 --- a/postgresql/resource_postgresql_database.go +++ b/postgresql/resource_postgresql_database.go @@ -570,4 +570,4 @@ func terminateBConnections(c *Client, dbName string) error { } return nil -} \ No newline at end of file +} From 9c801b582dcabbc3694fde0f11828479772b86a0 Mon Sep 17 00:00:00 2001 From: p4cket Date: Sun, 6 Dec 2020 14:21:31 -0500 Subject: [PATCH 5/9] support for other psql versions --- postgresql/config.go | 10 ++++++++++ postgresql/resource_postgresql_database.go | 18 +++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/postgresql/config.go b/postgresql/config.go index 371831b9..ebc3e528 100644 --- a/postgresql/config.go +++ b/postgresql/config.go @@ -25,6 +25,8 @@ const ( featureReplication featureExtension featurePrivileges + featureForceDrop + featurePid ) type dbRegistryEntry struct { @@ -65,6 +67,14 @@ var ( // We do not support postgresql_grant and postgresql_default_privileges // for Postgresql < 9. featurePrivileges: semver.MustParseRange(">=9.0.0"), + + // DROP DATABASE WITH FORCE + // for Postgresql >= 13 + featureForceDrop: semver.MustParseRange(">=13.0.0"), + + // Column procpid was replaced by pid in pg_stat_activity + // for Postgresql >= 9.2 and above + featurePid: semver.MustParseRange(">=9.2.0"), } ) diff --git a/postgresql/resource_postgresql_database.go b/postgresql/resource_postgresql_database.go index 743508d8..ab995d86 100644 --- a/postgresql/resource_postgresql_database.go +++ b/postgresql/resource_postgresql_database.go @@ -233,6 +233,7 @@ func resourcePostgreSQLDatabaseDelete(d *schema.ResourceData, meta interface{}) currentUser := c.config.getDatabaseUsername() owner := d.Get(dbOwnerAttr).(string) + var dropWithForce string var err error if owner != "" { // Needed in order to set the owner of the db if the connection user is not a @@ -268,7 +269,13 @@ func resourcePostgreSQLDatabaseDelete(d *schema.ResourceData, meta interface{}) return err } - sql := fmt.Sprintf("DROP DATABASE %s", pq.QuoteIdentifier(dbName)) + // Drop with force only for psql 13+ + if c.featureSupported(featureForceDrop) { + dropWithForce = "WITH FORCE" + } + + sql := fmt.Sprintf("DROP DATABASE %s %s", pq.QuoteIdentifier(dbName), dropWithForce) + if _, err := c.DB().Exec(sql); err != nil { return fmt.Errorf("Error dropping database: %w", err) } @@ -555,6 +562,8 @@ func doSetDBIsTemplate(c *Client, dbName string, isTemplate bool) error { } func terminateBConnections(c *Client, dbName string) error { + var terminateSql string + if c.featureSupported(featureDBAllowConnections) { alterSql := fmt.Sprintf("ALTER DATABASE %s ALLOW_CONNECTIONS false", pq.QuoteIdentifier(dbName)) @@ -562,8 +571,11 @@ func terminateBConnections(c *Client, dbName string) error { return fmt.Errorf("Error blocking connections to database: %w", err) } } - - terminateSql := fmt.Sprintf("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '%s' AND pid <> pg_backend_pid()", dbName) + if c.featureSupported(featurePid) { + terminateSql = fmt.Sprintf("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '%s' AND pid <> pg_backend_pid()", dbName) + } else { + terminateSql = fmt.Sprintf("SELECT pg_terminate_backend(pg_stat_activity.procpid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '%s' AND procpid <> pg_backend_pid()", dbName) + } if _, err := c.DB().Exec(terminateSql); err != nil { return fmt.Errorf("Error terminating database connections: %w", err) From 202febb6544b3da863a5a6c39d64e1940b6db8d5 Mon Sep 17 00:00:00 2001 From: Michal Gorniak Date: Sat, 12 Dec 2020 15:37:35 -0500 Subject: [PATCH 6/9] Update postgresql/resource_postgresql_database.go Co-authored-by: Cyril Gaudin --- postgresql/resource_postgresql_database.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/postgresql/resource_postgresql_database.go b/postgresql/resource_postgresql_database.go index ab995d86..998f560f 100644 --- a/postgresql/resource_postgresql_database.go +++ b/postgresql/resource_postgresql_database.go @@ -571,12 +571,12 @@ func terminateBConnections(c *Client, dbName string) error { return fmt.Errorf("Error blocking connections to database: %w", err) } } + pid := "procpid" if c.featureSupported(featurePid) { - terminateSql = fmt.Sprintf("SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '%s' AND pid <> pg_backend_pid()", dbName) - } else { - terminateSql = fmt.Sprintf("SELECT pg_terminate_backend(pg_stat_activity.procpid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '%s' AND procpid <> pg_backend_pid()", dbName) + pid = "pid" + } + terminateSql = fmt.Sprintf("SELECT pg_terminate_backend(%s) FROM pg_stat_activity WHERE datname = '%s' AND %s <> pg_backend_pid()", pid, pid, dbName) } - if _, err := c.DB().Exec(terminateSql); err != nil { return fmt.Errorf("Error terminating database connections: %w", err) } From 79fb9053cf9a4e7e990a94b874b028997f36185b Mon Sep 17 00:00:00 2001 From: Cyril Gaudin Date: Sun, 13 Dec 2020 15:43:56 +0100 Subject: [PATCH 7/9] Update postgresql/resource_postgresql_database.go --- postgresql/resource_postgresql_database.go | 1 - 1 file changed, 1 deletion(-) diff --git a/postgresql/resource_postgresql_database.go b/postgresql/resource_postgresql_database.go index 998f560f..8bbf75d4 100644 --- a/postgresql/resource_postgresql_database.go +++ b/postgresql/resource_postgresql_database.go @@ -576,7 +576,6 @@ func terminateBConnections(c *Client, dbName string) error { pid = "pid" } terminateSql = fmt.Sprintf("SELECT pg_terminate_backend(%s) FROM pg_stat_activity WHERE datname = '%s' AND %s <> pg_backend_pid()", pid, pid, dbName) - } if _, err := c.DB().Exec(terminateSql); err != nil { return fmt.Errorf("Error terminating database connections: %w", err) } From 1a29b88421aa66fce08aee418fed094e7b8ab795 Mon Sep 17 00:00:00 2001 From: Cyril Gaudin Date: Thu, 24 Dec 2020 14:02:46 +0100 Subject: [PATCH 8/9] Update postgresql/resource_postgresql_database.go --- postgresql/resource_postgresql_database.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgresql/resource_postgresql_database.go b/postgresql/resource_postgresql_database.go index 8bbf75d4..b2160bc8 100644 --- a/postgresql/resource_postgresql_database.go +++ b/postgresql/resource_postgresql_database.go @@ -271,7 +271,7 @@ func resourcePostgreSQLDatabaseDelete(d *schema.ResourceData, meta interface{}) // Drop with force only for psql 13+ if c.featureSupported(featureForceDrop) { - dropWithForce = "WITH FORCE" + dropWithForce = "WITH FORCE" } sql := fmt.Sprintf("DROP DATABASE %s %s", pq.QuoteIdentifier(dbName), dropWithForce) From 3a59e193748bbd29fee614bc208bbdb454eca55a Mon Sep 17 00:00:00 2001 From: Cyril Gaudin Date: Fri, 25 Dec 2020 10:26:39 +0100 Subject: [PATCH 9/9] fixup! Update postgresql/resource_postgresql_database.go --- postgresql/config.go | 4 ++-- postgresql/resource_postgresql_database.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/postgresql/config.go b/postgresql/config.go index ebc3e528..3a57db85 100644 --- a/postgresql/config.go +++ b/postgresql/config.go @@ -25,7 +25,7 @@ const ( featureReplication featureExtension featurePrivileges - featureForceDrop + featureForceDropDatabase featurePid ) @@ -70,7 +70,7 @@ var ( // DROP DATABASE WITH FORCE // for Postgresql >= 13 - featureForceDrop: semver.MustParseRange(">=13.0.0"), + featureForceDropDatabase: semver.MustParseRange(">=13.0.0"), // Column procpid was replaced by pid in pg_stat_activity // for Postgresql >= 9.2 and above diff --git a/postgresql/resource_postgresql_database.go b/postgresql/resource_postgresql_database.go index b2160bc8..b21c7d83 100644 --- a/postgresql/resource_postgresql_database.go +++ b/postgresql/resource_postgresql_database.go @@ -270,8 +270,8 @@ func resourcePostgreSQLDatabaseDelete(d *schema.ResourceData, meta interface{}) } // Drop with force only for psql 13+ - if c.featureSupported(featureForceDrop) { - dropWithForce = "WITH FORCE" + if c.featureSupported(featureForceDropDatabase) { + dropWithForce = "WITH ( FORCE )" } sql := fmt.Sprintf("DROP DATABASE %s %s", pq.QuoteIdentifier(dbName), dropWithForce) @@ -575,7 +575,7 @@ func terminateBConnections(c *Client, dbName string) error { if c.featureSupported(featurePid) { pid = "pid" } - terminateSql = fmt.Sprintf("SELECT pg_terminate_backend(%s) FROM pg_stat_activity WHERE datname = '%s' AND %s <> pg_backend_pid()", pid, pid, dbName) + terminateSql = fmt.Sprintf("SELECT pg_terminate_backend(%s) FROM pg_stat_activity WHERE datname = '%s' AND %s <> pg_backend_pid()", pid, dbName, pid) if _, err := c.DB().Exec(terminateSql); err != nil { return fmt.Errorf("Error terminating database connections: %w", err) }