Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV
Hi all,
Im having trouble with QSqlDatabase::addDatabase. I have a PostgresDriver class which I use for connecting to DB and making some queries. I can create any of these in the main cpp file. However I also have an HTTPServer which depending on the request, also creates a PostgresDriver to . This is where the QSqlDatabase::addDatabase() (and for what I can see in the stack trace, in its inner moveToThread) crashes.
I've read all the posts and documentation saying that connections are not thread safe and that should not be reused in other threads. I also presume that the HTTPSERVER will handle the requests spreaded in different threads and therefore the place where I am creating the new PostgresDriver is no the main thread. But for what I understood there should not be any problem if what I am doing is creating a new connection (not reusing one from another thread).
Code:
///////////////////////////////////////////////////////// POSTGRESDRIVER.H
class PostgresDriver
: public QObject{
public:
~PostgresDriver();
QList<QSqlRecord> executeQuery
(QString sql
);
private:
};
///////////////////////////////////////////////////////// POSTGRESDRIVER.CPP
#include "PostgresDriver.h"
{
this->connection_name = connection_name;
this
->database
= QSqlDatabase::addDatabase("QPSQL" , this
->connection_name
);
// HERE IS WHERE IT BREAKS IF DRIVER IS CREATED NOT IN THE MAIN THREAD this->database.setHostName( url );
this->database.setPort( port );
this->database.setDatabaseName( db_name );
this->database.setUserName( db_user );
this->database.setPassword( db_pass );
while( !this->database.open() ){
this->thread()->sleep( 2 ); // Wait 2 seconds
qWarning() << "[PostgresDriver::connectDB] Unable to connect to DB : " << this->database.hostName() << this->database.port() << this->database.databaseName() << " waiting..." << endl;
}
}
PostgresDriver::~PostgresDriver(){
this->database.close();
this->database.removeDatabase( this->connection_name );
}
QList<QSqlRecord> PostgresDriver
::executeQuery( QString sql
){
QList<QSqlRecord> list;
if( this->database.isOpen() ){
QSqlQuery query
( this
->database.
database( this
->connection_name
) );
query.exec( sql );
qWarning() << error.text() << endl << sql << endl;
}
while( query.next() ){
list.append(query.record());
}
} else {
qWarning() << "[PostgresDriver::executeQuery] Could not execute query because database is closed." << endl;
}
return list;
}
STACK TRACE:
0 QObject::moveToThread(QThread *) 0x7fb1885167a7
1 QFactoryLoader::instance(int) const 0x7fb1884c9df5
2 ?? 0x7fb188d42c74
3 QSqlDatabase::addDatabase(QString const&, QString const&) 0x7fb188d431f1
4 PostgresDriver::PostgresDriver PostgresDriver.cpp 12 0x4233aa // MY POSTGRESDRIVER CLASS
5 RequestHandler::HTTP_Create RequestHandler.cpp 175 0x41667e // MY HTTPSERVER REQUEST HANDLER
I've even tried creating a centralized DBController which was created in the main thread and dispatched connections to other threads but same thing happened. Any clues about this?
Thanks in advance
Re: Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV
SQL module is NOT thread safe.
Connection name must be unique for every thread.
P.S.
While loop waiting for db open is "never ending loop" if they are having connecting problems.
Re: Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV
Even if the connection_name is unique for every thread It still throws the SIGSEGV. :(
Re: Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV
Show how are You using this class.
Re: Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV
Code:
///////////////////////////////////////////////////////// MAIN.CPP
PostgresDriver* driver = new PostgresDriver("localhost" , 5432 , "database" , "user" , "user" , "main");
QListIterator<QSqlRecord> i( driver->executeQuery( "SELECT * FROM WHATEVER" ) );
while( i.hasNext() ){
}
driver->deleteLater();
Works perfectly.
Now:
Code:
///////////////////////////////////////////////////////// AGENT.H
{
Q_OBJECT
public:
Agent
(QString class_name
= "Agent");
~Agent();
// GETTERS
unsigned int getId();
slots:
virtual void start();
virtual void end(){this->deleteLater();}
private:
// INCREMENTAL FOR IDS
static unsigned int counter;
unsigned int id;
};
///////////////////////////////////////////////////////// AGENT.CPP
#include "Agent.h"
unsigned int Agent::counter = 0;
{
this->id = ++Agent::counter;
this->class_name = class_name;
this
->setObjectName
( QString("%1%2").
arg( this
->getClass
() ).
arg( this
->getId
() ) );
}
Agent::~Agent() {
this->thread()->deleteLater();
}
unsigned int Agent::getId(){
return this->id;
}
return this->class_name;
}
void Agent::start(){
PostgresDriver* db = new PostgresDriver("localhost" , 5432 , "database" , "user" , "user" , this->objectName() ); //CRASHES
}
///////////////////////////////////////////////////////// MAIN.CPP
Agent* agent = new Agent("Car");
agent->moveToThread( thread );
agent->connect( thread, SIGNAL( started() ), agent, SLOT( start() ) );
thread->start();
Crashes when creating a PostgresDriver inside the Agent.
Re: Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV
Why don't you create the connection from your thread? i.e. your start slot?