0

I have two QSqlDatabase database connections, "local" and "remote". I have a function that uses both connections (get data from local db and send to remote db). When I run this function from my QThread class, the local connection works (I got expected data), but the remote connection fails. But if I run this function outside the QThread class (in main()), both connections works.

The remote connection fails when I try to open the connection with the error message: "QSqlDatabasePrivate::database: unable to open database: QMYSQL: Unable to connect". Before that I tested to see if the connection was valid (isValid()) and it was okey. I also check if the connection already was open, but it wasn't.

I also found this information, but since the "local" connection works from the thread this might not be the issue:

Threads and the SQL Module A connection can only be used from within the thread that created it. Moving connections between threads or creating queries from a different thread is not supported. http://doc.qt.io/qt-5/threads-modules.html#threads-and-the-sql-module

The error is found in Qt 5.5.1, 32bit, Ubuntu 14.04. Also tested on Raspberry Pi, Qt 5.6, but with "Segmentation fault" as result.

What is wrong?

main.c

main()
{
  DataHandler dh();
  DataHandlerThread dht(&dh); //pointer to dh to get access to dh functions from the thread

  //here I run dh.foo() or dht.run(), never both functions
  dh.foo();
  dht.run();
  ...
}

datahandler.cpp

DataHandler::DataHandler()
{
  m_dbLocal = QSqlDatabase::addDatabase("QMYSQL", "local");
  m_dbLocal.setHostName("localhost");
  ...

  m_dbRemote = QSqlDatabase::addDatabase("QMYSQL", "remote");
  m_dbRemote.setHostName(...);
  ...
}

DataHandler::foo()
{
  qDebug() << QSqlDatabase::connectionNames(); //always ("remote", "local")
  m_dbLocal.isValid(); //always true
  m_dbLocal.open(); //always true

  m_dbRemote.isValid(); //always true

  //true if foo() is called from main using dm.foo()
  //QSqlDatabasePrivate::database: unable to open database: " QMYSQL: Unable to connect" if called from main using dmt.run()
  m_dbRemote.open(); 
}

datahandlerthread.h

class DataHandlerThread : public QThread
{
    Q_OBJECT
public:
    explicit DataHandlerThread(DataHandler* dh);

private:
    void run() Q_DECL_OVERRIDE;

    DataHandler* m_dh;

};

datahandlerthread.cpp

DataHandlerThread::DataHandlerThread(DataHandler* dh)
{
    m_dh = dh;
}

void DataHandlerThread::run()
{
    m_dh->foo();
}
Peder
  • 157
  • 1
  • 1
  • 9

1 Answers1

1

I found a solution to the problem. The solution was to create new instances of both the local and the remote connection in the DataHandlerThread constructor:

datahandlerthread.cpp

DataHandlerThread::DataHandlerThread(DataHandler* dh)
{
  m_dh = dh;
  m_dbLocal = QSqlDatabase::addDatabase("QMYSQL", "local_thread");
  m_dbLocal.setHostName("localhost");
  ...

  m_dbRemote = QSqlDatabase::addDatabase("QMYSQL", "remote_thread");
  m_dbRemote.setHostName(...);
  ...
}

As I understand it, these new instances could also been created by using QSqlDatabase::cloneDatabase() and passed these new instances to the DataHandlerThread constructor (not tested).

So, it seems like the information in the "Threads and the SQL Module" link was somewhat correct. For some reason the "local" connection still worked from the thread.

Peder
  • 157
  • 1
  • 1
  • 9