Dans mon cas, j'utilise AWS Redshift (basé sur Postgres). Et il semble qu'il n'y ait pas d'autres connexions à la base de données, mais je reçois cette même erreur.
ERROR: database "XYZ" is being accessed by other users
Dans mon cas, il semble que le cluster de base de données effectue toujours un traitement sur la base de données, et bien qu'il n'y ait pas d'autres connexions externes/utilisateurs, la base de données est toujours utilisée en interne. J'ai découvert cela en exécutant ce qui suit :
SELECT * FROM stv_sessions;
Mon astuce a donc consisté à écrire une boucle dans mon code, à la recherche de lignes contenant le nom de ma base de données. (bien sûr la boucle n'est pas infinie, et est une boucle de sommeil, etc)
SELECT * FROM stv_sessions where db_name = 'XYZ';
Si des lignes sont trouvées, supprimez chaque PID, un par un.
SELECT pg_terminate_backend(PUT_PID_HERE);
Si aucune ligne n'a été trouvée, il faut abandonner la base de données.
DROP DATABASE XYZ;
Note : Dans mon cas, j'écris des tests unitaires/systèmes Java, où cela pourrait être considéré comme acceptable. Ce n'est pas acceptable pour un code de production.
Voici le hack complet, en Java (ignorez mes classes de test/utilité).
int i = 0;
while (i < 10) {
try {
i++;
logStandardOut("First try to delete session PIDs, before dropping the DB");
String getSessionPIDs = String.format("SELECT stv_sessions.process, stv_sessions.* FROM stv_sessions where db_name = '%s'", dbNameToReset);
ResultSet resultSet = databaseConnection.execQuery(getSessionPIDs);
while (resultSet.next()) {
int sessionPID = resultSet.getInt(1);
logStandardOut("killPID: %s", sessionPID);
String killSessionPID = String.format("select pg_terminate_backend(%s)", sessionPID);
try {
databaseConnection.execQuery(killSessionPID);
} catch (DatabaseException dbEx) {
//This is most commonly when a session PID is transient, where it ended between my query and kill lines
logStandardOut("Ignore it, you did your best: %s, %s", dbEx.getMessage(), dbEx.getCause());
}
}
//Drop the DB now
String dropDbSQL = String.format("DROP DATABASE %s", dbNameToReset);
logStandardOut(dropDbSQL);
databaseConnection.execStatement(dropDbSQL);
break;
} catch (MissingDatabaseException ex) {
//ignore, if the DB was not there (to be dropped)
logStandardOut(ex.getMessage());
break;
} catch (Exception ex) {
logStandardOut("Something went wrong, sleeping for a bit: %s, %s", ex.getMessage(), ex.getCause());
sleepMilliSec(1000);
}
}