Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSqlQuery crashes when inserting large bytea data
Forum Updated to NodeBB v4.3 + New Features

QSqlQuery crashes when inserting large bytea data

Scheduled Pinned Locked Moved Unsolved General and Desktop
24 Posts 3 Posters 2.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • X Offline
    X Offline
    xyfix
    wrote on last edited by
    #8

    Christian, you're absolutely right and that's why I try to create a connection in the thread that I start. I hoped by including the partial code of db.cpp it would illustrate that. I used the threadstorage class to create and hold the connection data. But what I see is that the future is in the ready status while the upload is not done, any ideas?

    Christian EhrlicherC 1 Reply Last reply
    0
    • X xyfix

      Christian, you're absolutely right and that's why I try to create a connection in the thread that I start. I hoped by including the partial code of db.cpp it would illustrate that. I used the threadstorage class to create and hold the connection data. But what I see is that the future is in the ready status while the upload is not done, any ideas?

      Christian EhrlicherC Online
      Christian EhrlicherC Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #9

      @xyfix I've overseen s_databaseConnections.

      You should try to make it work without threads first anyway.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      0
      • X Offline
        X Offline
        xyfix
        wrote on last edited by xyfix
        #10

        Yes, I did and that works ( just takes ages to upload :-) ) but eventually everything gets uploaded to the db. I have checked with octet_length whether the blob size in postgresql is correct and it is. I have also check with qDebug statements and saw that new connections are made to the database for each thread started.

        1 Reply Last reply
        0
        • Christian EhrlicherC Online
          Christian EhrlicherC Online
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #11

          One more thing - cloneDatabse had some issues with the threadsafety. Can you, for testing, create a completely new db connection?

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          1 Reply Last reply
          0
          • X Offline
            X Offline
            xyfix
            wrote on last edited by xyfix
            #12

            Ok , I have replaced the cloneDatabase() with this . but no success.

                QString connectionName = QString("conn_%1").arg(++connectionCounter);
            
                QSqlDatabase dbConnection = QSqlDatabase::addDatabase("QPSQL", connectionName );
                dbConnection.setDatabaseName( m_database->sqlDb().databaseName());
                dbConnection.setHostName( m_database->sqlDb().hostName());
                dbConnection.setPort( m_database->sqlDb().port());
                dbConnection.setUserName( m_database->sqlDb().userName());
                dbConnection.setPassword( m_database->sqlDb().password());
            

            edit: I have added some more qDebug statements to make sure that I'm sending blob data and i have verified that it's sending. But the file does not reach the database. of the 20 files in the for loop only 5 entries reach the database and they are all 0 Kb.

            1 Reply Last reply
            0
            • Christian EhrlicherC Online
              Christian EhrlicherC Online
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on last edited by
              #13

              @xyfix said in QSqlQuery crashes when inserting large bytea data:

              DAL::getInstance().Media()->addMediaRecord( mediaData );

              Are you sure you use the correct db connection here?

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              1 Reply Last reply
              0
              • X Offline
                X Offline
                xyfix
                wrote on last edited by
                #14

                @Christian-Ehrlicher , after splitting the large file into smaller pieces I don't get any crashes anymore, it's just that the parallel version does not upload any files ( all are 0 Kb) while the sequential version uploads all correctly. I have put a qDebug statement in the function that is called by SqlQueryExecutor::execute() and the database is the newly created one "conn_3", "conn_4".....

                
                std::shared_ptr<SqlQueryStatement> SqlQueryExecutor::execute( const QString& query, const SqlQueryData& sqlData)
                {
                qDebug() << "execute db " << Db::db()->database()->sqlDb().connectionName();
                    std::shared_ptr< SqlQueryStatement > statement( new SqlQueryStatement( Db::db()->database(), query, sqlData ));
                
                    return statement;
                }
                
                
                
                1 Reply Last reply
                0
                • Christian EhrlicherC Online
                  Christian EhrlicherC Online
                  Christian Ehrlicher
                  Lifetime Qt Champion
                  wrote on last edited by Christian Ehrlicher
                  #15

                  @xyfix said in QSqlQuery crashes when inserting large bytea data:

                  DAL::getInstance().Media()->addMediaRecord( mediaData );

                  I still don't understand how this function can fetch the thread local database since you don't pass it - how do you access the db in there?

                  Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                  Visit the Qt Academy at https://academy.qt.io/catalog

                  1 Reply Last reply
                  0
                  • X Offline
                    X Offline
                    xyfix
                    wrote on last edited by
                    #16

                    @Christian-Ehrlicher, I hope this explains a couple of things along with the previous posted code. The Database class has the SqlDatabase object

                    dal.h

                        static DAL& getInstance()
                        {
                            static DAL instance;
                            return instance;
                        }
                    
                        TblMedia*    Media()  { return m_dbMedia.get(); }
                    
                        std::unique_ptr< TblMedia >  m_dbMedia;
                    

                    dal.cpp

                    DAL::DAL()
                    {
                        m_dbMedia.reset( new TblMedia());
                    }
                    

                    tblmedia.h

                    class TblExaminationMedia
                    {
                    public:
                    
                        explicit TblMedia();
                    
                        int addMediaRecord( const MediaData& file );
                    }
                    

                    tblmedia.cpp

                    int TblExaminationMedia::addExaminationMediaRecord(const ExaminationMediaData &file )
                    {
                        std::shared_ptr< SqlQueryStatement > statement = SqlQueryExecutor::execute( "INSERT INTO media ( fileid, typeid, movie, creationtime ) "
                                                         "VALUES (?,?,?,? )", SqlQueryData().add( file.m_fileId ).add( file.m_typeId ).add( file.m_movie ).add( file.m_creationtime ));
                    
                        return statement->getResult() ? statement->getLastInsertedId() : -1;
                    }
                    

                    sqlqueryexecutor.h

                        std::shared_ptr< SqlQueryStatement > execute( const QString& query, const SqlQueryData& sqlData = SqlQueryData());
                    

                    sqlqueryexecutor.cpp

                    std::shared_ptr<SqlQueryStatement> SqlQueryExecutor::execute( const QString& query, const SqlQueryData& sqlData)
                    {
                        std::shared_ptr< SqlQueryStatement > statement( new SqlQueryStatement( Db::db()->database(), query, sqlData ));
                    
                        return statement;
                    }
                    
                    1 Reply Last reply
                    0
                    • Christian EhrlicherC Online
                      Christian EhrlicherC Online
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #17

                      Looks a little bit over-designed but in theory it's fine. I would start using a memory analyzer like e.g. valgrind. Or really use a simple QSqlQuery + bindValue() in the thread just to be sure.

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      1 Reply Last reply
                      0
                      • X Offline
                        X Offline
                        xyfix
                        wrote on last edited by xyfix
                        #18

                        Ok, keep you updated. I also debugged all the way when qsqlquery.exec() is called and looked at the database connection that is used and it's the right one "conn_3" or "conn_4".... so on connection level it looks ok

                        1 Reply Last reply
                        0
                        • SGaistS Offline
                          SGaistS Offline
                          SGaist
                          Lifetime Qt Champion
                          wrote on last edited by
                          #19

                          I may have missed it but are you sure you are creating the connections within the thread and not before ?

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          Christian EhrlicherC 1 Reply Last reply
                          0
                          • SGaistS SGaist

                            I may have missed it but are you sure you are creating the connections within the thread and not before ?

                            Christian EhrlicherC Online
                            Christian EhrlicherC Online
                            Christian Ehrlicher
                            Lifetime Qt Champion
                            wrote on last edited by
                            #20

                            @SGaist It should - it's a QThreadLocal storage.

                            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                            Visit the Qt Academy at https://academy.qt.io/catalog

                            1 Reply Last reply
                            0
                            • X Offline
                              X Offline
                              xyfix
                              wrote on last edited by xyfix
                              #21

                              @SGaist , I have carefully placed QDebug statements within the thread and I see the "conn_%1" connections being used. I just found out that it "crashes" when qsqlquery.exec() is executed but nothing gets printed with lastError(). This only happens when I use threads without the threads it's ok and using the same code.

                              1 Reply Last reply
                              0
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #22

                                Rather than using a counter, I would use the thread ID to build the name, thus would have the added benefit of ensuring that you are not creating the same connection twice.

                                Same goes for the debug messages, add the main thread and current thread ID just to be sure your code executed in the context you expect.

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                1 Reply Last reply
                                0
                                • X Offline
                                  X Offline
                                  xyfix
                                  wrote on last edited by xyfix
                                  #23

                                  I followed the advice of @Christian-Ehrlicher and tried this approach, directly creating a connection in the thread and using qsqlquery in that thread so it doesn't use my code, but this also doesn't upload anything to the db while the connection is OK

                                             std::vector< std::future< bool > > futures;
                                  
                                              for( auto filename : fileList())
                                              {
                                  qDebug() << "file " << filename;
                                                      std::future< bool > futureDb = std::async( std::launch::async, [ this, &filename ]()->bool
                                                      {
                                                          QFile movie( filename );
                                                          bool result( false );
                                  
                                                          if( !movie.exists())
                                                              return result;                       
                                  
                                                          movie.open( QIODevice::ReadOnly );
                                  
                                  
                                                          QString connectionName = QString("conn_%1").arg( int( QThread::currentThreadId()));
                                  
                                                          QSqlDatabase dbConnection = QSqlDatabase::addDatabase("QPSQL", connectionName );
                                                          dbConnection.setDatabaseName( "MYDB" );
                                                          dbConnection.setHostName( "localhost" );
                                                          dbConnection.setPort( 5432 );
                                                          dbConnection.setUserName( "testuser" );
                                                          dbConnection.setPassword( "test123" );
                                  
                                                          if( !dbConnection.open())
                                                              qDebug() << "unable to open db";
                                  
                                                          QString str = QString( "INSERT INTO media ( fileid, typeid, movie, creationtime ) "
                                                                   "VALUES ( :val1,:val2,:val3,:val4 )");
                                  
                                                          QSqlQuery qry( dbConnection );
                                                          qry.prepare( str );
                                                          qry.bindValue( ":val1", 5 );
                                                          qry.bindValue( ":val2", 2 );
                                                          qry.bindValue( ":val3", movie.readAll().toBase64());
                                                          qry.bindValue( ":val4", QDateTime::currentDateTime());
                                  
                                                          qry.exec();
                                  
                                  qDebug() << filename << " stored in db result " << result.getError().text();
                                  
                                                          movie.close();
                                                          dbConnection.close();
                                  
                                                          return result;
                                  
                                                      });
                                  
                                                      futures.push_back( std::move( futureDb ));
                                  
                                  
                                                      while( futures.size() > 1 )
                                                      {
                                                          for( auto& future : futures )
                                                          {
                                                              if( future.wait_for( std::chrono::seconds(0)) == std::future_status::ready )
                                                              {
                                                                  std::swap( future, futures.back());
                                                                  futures.pop_back();
                                  
                                                                  break;
                                                              }
                                                          }
                                                      }
                                  
                                  1 Reply Last reply
                                  0
                                  • SGaistS Offline
                                    SGaistS Offline
                                    SGaist
                                    Lifetime Qt Champion
                                    wrote on last edited by
                                    #24

                                    One thing I would add is the check that open was successful. The fact that the file exists does not mean you can access it.

                                    Interested in AI ? www.idiap.ch
                                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                    1 Reply Last reply
                                    0

                                    • Login

                                    • Login or register to search.
                                    • First post
                                      Last post
                                    0
                                    • Categories
                                    • Recent
                                    • Tags
                                    • Popular
                                    • Users
                                    • Groups
                                    • Search
                                    • Get Qt Extensions
                                    • Unsolved