I found other similar questions with the same error (i.e. this and this) but apparently all of them are related to a wrong library / configuration since the users cannot connect to the database at all.
In my case instead I can successfully connect to the remote SQLServer database. The error comes up only when the remote host goes down and then comes back online. In this case I receive:
[unixODBC][Driver Manager]Driver's SQLAllocHandle on SQL_HANDLE_HENV failed"
until I restart my application. Here the code I use to connect to the database:
bool OdbcSql::connectToDB(QUrl host, QString database, QString username, QString password)
{
_host = host;
_database = database;
_username = username;
_password = password;
if (_db.isOpen()) _db.close();
_db.removeDatabase("production");
_db = QSqlDatabase::addDatabase("QODBC", "production");
qInfo() << ID << "Trying to open database...";
_db.setDatabaseName(QStringLiteral("Driver=/opt/microsoft/msodbcsql18/lib64/libmsodbcsql-18.2.so.1.1; Server=%1;Database=%2; Encrypt=No;").arg(host.url()).arg(database));
_db.setUserName(username);
_db.setPassword(password);
_db.setConnectOptions("SQL_ATTR_CONNECTION_TIMEOUT=5;SQL_ATTR_LOGIN_TIMEOUT=5;SQL_ATTR_CONNECTION_POOLING=SQL_CP_OFF;");
bool ret = _db.open();
if (ret) qInfo() << ID << "Database opened successfully";
else qWarning() << ID << "Database opening failed:" << _db.lastError();
return ret;
}
I'm using Ubuntu 22.04, Qt 6.4.0, libmsodbcsql-18.2 as odbc driver.
UPDATE
Here the complete sequence to replicate the behavior.
- start my application
- let's say the remote host is not available (offline)
- the connect fails due to login timeout
- every minute it tries again, calling the function above
- the remote host is online
- the connect works and I can use the database
- after some time the remote host goes offline
- I detect the loss of connection (see below)
- every minute it tries again, calling the function above but it fails due to timeout login
- the remote host comes back online
- I get the
SQL_HANDLE_HENVerror - the online way to connect again to the database is to stop and run again my application
Here the code I use to detect the loss of connection:
bool OdbcSql::checkConnectivity()
{
if (!_isConnected) return false;
if (_db.transaction())
{
_db.rollback();
return true;
}
else
{
_isConnected = false;
_db.close();
qWarning() << ID << "Lost connection to database";
return false;
}
}
I cannot use the QSqlDatabase::isOpen() method because it does not return the actual state of the connection. I found this code here on StackOverflow and in the QtForum.
QSqlDatabase db = QSqlDatabase::database("sales");in every function so it gets destroyed when it exits the function?