Results 1 to 6 of 6

Thread: Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV

  1. #1
    Join Date
    Apr 2015
    Posts
    8
    Thanks
    3

    Default 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).


    Qt Code:
    1. ///////////////////////////////////////////////////////// POSTGRESDRIVER.H
    2.  
    3. class PostgresDriver : public QObject
    4. {
    5. public:
    6. PostgresDriver(QString url, int port, QString db_name, QString db_user, QString db_pass, QString connection_name = "shared_connection");
    7. ~PostgresDriver();
    8. QList<QSqlRecord> executeQuery(QString sql);
    9.  
    10. private:
    11. QSqlDatabase database;
    12. QString connection_name;
    13. };
    14.  
    15. ///////////////////////////////////////////////////////// POSTGRESDRIVER.CPP
    16.  
    17. #include "PostgresDriver.h"
    18.  
    19. PostgresDriver::PostgresDriver(QString url, int port, QString db_name, QString db_user, QString db_pass, QString connection_name) : QObject()
    20. {
    21. this->connection_name = connection_name;
    22.  
    23. this->database = QSqlDatabase::addDatabase("QPSQL" , this->connection_name); // HERE IS WHERE IT BREAKS IF DRIVER IS CREATED NOT IN THE MAIN THREAD
    24. this->database.setHostName( url );
    25. this->database.setPort( port );
    26. this->database.setDatabaseName( db_name );
    27. this->database.setUserName( db_user );
    28. this->database.setPassword( db_pass );
    29.  
    30. while( !this->database.open() ){
    31. this->thread()->sleep( 2 ); // Wait 2 seconds
    32. qWarning() << "[PostgresDriver::connectDB] Unable to connect to DB : " << this->database.hostName() << this->database.port() << this->database.databaseName() << " waiting..." << endl;
    33. }
    34. }
    35.  
    36. PostgresDriver::~PostgresDriver(){
    37. this->database.close();
    38. this->database.removeDatabase( this->connection_name );
    39. }
    40.  
    41. QList<QSqlRecord> PostgresDriver::executeQuery( QString sql ){
    42.  
    43. QList<QSqlRecord> list;
    44.  
    45. if( this->database.isOpen() ){
    46. QSqlQuery query( this->database.database( this->connection_name ) );
    47.  
    48. query.exec( sql );
    49.  
    50. QSqlError error = query.lastError();
    51. if (error.type() != QSqlError::NoError){
    52. qWarning() << error.text() << endl << sql << endl;
    53. }
    54.  
    55. while( query.next() ){
    56. list.append(query.record());
    57. }
    58.  
    59. } else {
    60. qWarning() << "[PostgresDriver::executeQuery] Could not execute query because database is closed." << endl;
    61. }
    62.  
    63. return list;
    64. }
    To copy to clipboard, switch view to plain text mode 

    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

  2. #2
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default 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.
    Last edited by Lesiok; 6th May 2015 at 10:57.

  3. #3
    Join Date
    Apr 2015
    Posts
    8
    Thanks
    3

    Default 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.

  4. #4
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV

    Show how are You using this class.

  5. #5
    Join Date
    Apr 2015
    Posts
    8
    Thanks
    3

    Default Re: Calling QSqlDatabase::addDatabase from not main thread causes SIGSEGV

    Qt Code:
    1. ///////////////////////////////////////////////////////// MAIN.CPP
    2.  
    3. PostgresDriver* driver = new PostgresDriver("localhost" , 5432 , "database" , "user" , "user" , "main");
    4.  
    5. QListIterator<QSqlRecord> i( driver->executeQuery( "SELECT * FROM WHATEVER" ) );
    6. while( i.hasNext() ){
    7. }
    8. driver->deleteLater();
    To copy to clipboard, switch view to plain text mode 
    Works perfectly.

    Now:

    Qt Code:
    1. ///////////////////////////////////////////////////////// AGENT.H
    2.  
    3. class Agent : public QObject
    4. {
    5. Q_OBJECT
    6. public:
    7. Agent(QString class_name = "Agent");
    8. ~Agent();
    9.  
    10. // GETTERS
    11. unsigned int getId();
    12. QString getClass();
    13.  
    14. slots:
    15. virtual void start();
    16. virtual void end(){this->deleteLater();}
    17.  
    18. private:
    19.  
    20. // INCREMENTAL FOR IDS
    21. static unsigned int counter;
    22.  
    23. unsigned int id;
    24. QString class_name;
    25. };
    26.  
    27. ///////////////////////////////////////////////////////// AGENT.CPP
    28.  
    29. #include "Agent.h"
    30.  
    31. unsigned int Agent::counter = 0;
    32.  
    33. Agent::Agent(QString class_name) : QObject()
    34. {
    35. this->id = ++Agent::counter;
    36. this->class_name = class_name;
    37. this->setObjectName( QString("%1%2").arg( this->getClass() ).arg( this->getId() ) );
    38. }
    39.  
    40. Agent::~Agent() {
    41. this->thread()->deleteLater();
    42. }
    43.  
    44. unsigned int Agent::getId(){
    45. return this->id;
    46. }
    47.  
    48. QString Agent::getClass(){
    49. return this->class_name;
    50. }
    51.  
    52. void Agent::start(){
    53. PostgresDriver* db = new PostgresDriver("localhost" , 5432 , "database" , "user" , "user" , this->objectName() ); //CRASHES
    54. }
    55.  
    56. ///////////////////////////////////////////////////////// MAIN.CPP
    57.  
    58. Agent* agent = new Agent("Car");
    59. QThread *thread = new QThread( );
    60. agent->moveToThread( thread );
    61. agent->connect( thread, SIGNAL( started() ), agent, SLOT( start() ) );
    62. thread->start();
    To copy to clipboard, switch view to plain text mode 
    Crashes when creating a PostgresDriver inside the Agent.

  6. #6
    Join Date
    Dec 2009
    Location
    New Orleans, Louisiana
    Posts
    791
    Thanks
    13
    Thanked 153 Times in 150 Posts
    Qt products
    Qt5
    Platforms
    MacOS X

    Default 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?

Similar Threads

  1. Replies: 1
    Last Post: 28th March 2012, 19:58
  2. Replies: 0
    Last Post: 2nd December 2011, 20:52
  3. Replies: 5
    Last Post: 22nd February 2011, 22:21
  4. Replies: 9
    Last Post: 28th November 2009, 21:31
  5. Replies: 16
    Last Post: 7th October 2009, 09:17

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.