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. QSqlQueryModel & QSqlQuery::prepare - app crash
Forum Updated to NodeBB v4.3 + New Features

QSqlQueryModel & QSqlQuery::prepare - app crash

Scheduled Pinned Locked Moved General and Desktop
12 Posts 3 Posters 5.0k 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.
  • M Offline
    M Offline
    michmu
    wrote on last edited by
    #1

    Hi,

    I'm using Qt 5.2.1, Qt Visual Studio Addin 1.2.2 , Visual Studio 2010, Win7. I work with PostgreSQL database @QSqlDatabase::addDatabase("QPSQL");@

    I have a problem using QSqlQueryModel with a QSqlQuery prepared by QSqlQuery::prepare() and QSqlQuery::exec(). I also described it on "stackoverflow":http://stackoverflow.com/questions/25660089/qsqlquerymodel-with-a-parent-app-crash
    Here's the problem: I have a class:
    @class searchDock : public QDockWidget
    {
    Q_OBJECT
    (...)
    QSqlQueryModel* model;
    }@

    I initialize the model like this:

    @model = new QSqlQueryModel(this);
    model->setObjectName("model"); //so that QMetaObject::​connectSlotsByName would work for the model's signals@

    Then - the model uses QSqlQuery query, that I prepare with a QSqlQuery::prepare method. I execute the query, and pass it to the model :
    @query.prepare(...);
    query.addBindValue(searchString);

    if (!query.exec()) {
    qDebug() << query.lastError();
    return;
    }
    model->setQuery(query);@

    And then I pass he model to a TableView:
    @ui.kontrahenciList->setModel(model);
    ui.kontrahenciList->show();@

    It all works as far. The problem is, that when I close the application, I get an error:

    bq. Unhandled exception at 0x0f0c9f9a (qsqlpsqld.dll) in HurBudClientGUI.exe: 0xC0000005: Access violation reading location 0x00000004.

    I do not delete anything manually anywhere .
    I wanted to paste a StackTrace here, but I can't (I get an error, that this post is spam). You can see the stacktrace on my stackoverflow question.

    The problem doesn't occur when I use "plain" QSqlQuery (without prepared statement). The problem also occurs, when I initialize the model without a parent, but delete it in the searchDock desctructor.
    So I have to initialize the model without a parent, and not delete it in my class' destructor - which leads to a memory leak.
    Did I do something wrong? I guess it may be a bug - I reported it (QTBUG-43889) , but nobody replied.

    I sometimes get the same error when using QSqlTableModel and QSqlRelationalTableModel , but it doesn't happen every time...
    Does anybody have an idea how to fix it? I upgraded Qt to current 5.4 version, but everything stayed the same - error still occurs...

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

      Hi and welcome to devnet,

      It would be even better if you could attach a minimal compilable example to your bug report, if possible with a minimal SQL dump file to recreate the database so it's possible to try and reproduce your crash more easily

      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
      • M Offline
        M Offline
        michmu
        wrote on last edited by
        #3

        I found out, that the error is triggered when I have this line:
        @QSqlDatabase::removeDatabase(QSqlDatabase::database().connectionName());@

        in my MainWindow::~MainWindow (destructor). Executing this line writes this:

        bq. QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.

        And next - the error is triggered. I heve just posted the code example to the bugreport (QTBUG-43889) .

        Is it sufficient to just call
        @QSqlDatabase::database().close();@

        to properly free the connection? Maybe I don't need to call QSqlDatabase::removeDatabase ?

        1 Reply Last reply
        0
        • C Offline
          C Offline
          clochydd
          wrote on last edited by
          #4

          Hi,
          try this in the destructor:
          @
          yourDatabase = QSqlDatabase();
          QSqlDatabase::removeDatabase(yourDatabase.connectionName());
          @

          1 Reply Last reply
          0
          • M Offline
            M Offline
            michmu
            wrote on last edited by
            #5

            [quote author="Clochydd" date="1422090466"]Hi,
            try this in the destructor:
            @
            yourDatabase = QSqlDatabase();
            QSqlDatabase::removeDatabase(yourDatabase.connectionName());
            @
            [/quote]

            Tried it - no effect:
            @dbTestGUI::~dbTestGUI()
            {
            QSqlDatabase db = QSqlDatabase::database();
            //db.close();
            QSqlDatabase::removeDatabase(db.connectionName()); //this line causes error
            }@

            1 Reply Last reply
            0
            • C Offline
              C Offline
              clochydd
              wrote on last edited by
              #6

              Hi,
              I always open my databases that way:
              @
              db = QSqlDatabase::addDatabase("QPSQL");
              db.setDatabaseName("myDB");
              db.setHostName("localhost");
              db.setPort(5432);
              if (!db.open("user", "password")) {
              ...
              }
              ...
              @

              and close it the destructor:

              @
              db = QSqlDatabase();
              QSqlDatabase::removeDatabase(db.connectionName());
              @

              1 Reply Last reply
              0
              • M Offline
                M Offline
                michmu
                wrote on last edited by
                #7

                According to the doc:

                bq. QSqlDatabase::​QSqlDatabase()
                Creates an empty, invalid QSqlDatabase object. Use addDatabase(), removeDatabase(), and database() to get valid QSqlDatabase objects.

                So I guess that you remove an invalid database - which probably doesn't do anything at all...

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  michmu
                  wrote on last edited by
                  #8

                  As i thought - when using your code - nothing happens. Neither is the connection closed (I can still see it it PgAdmin's "server status window":http://www.pgadmin.org/docs/dev/status.html), nor are the dll's unloaded. So I guess - that you'have been always closing it the wrong way :)

                  1 Reply Last reply
                  0
                  • C Offline
                    C Offline
                    clochydd
                    wrote on last edited by
                    #9

                    Just checked with pgAdmin's server status:
                    The connection appears when any of my postgres based programs is opened and disappears when the program is closed...

                    I came to the above described solution after several weeks of trial and error and with support by this forum.

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      michmu
                      wrote on last edited by
                      #10

                      Well, yes. The connection is created when you call QSqlDatabase::open. And it is closed as the application is closed - even if you don't call anything in the destructor. What I meant, is that if you execute and debug your code line-by-line - it does nothing.
                      Consider the following:
                      @dbTestGUI::~dbTestGUI()
                      {
                      QSqlDatabase db = QSqlDatabase();
                      qDebug() << db.isValid(); //returns false
                      db.close(); //does nothing - connection still visible in pgadmin server status
                      QSqlDatabase::removeDatabase(db.connectionName()); does nothig - no effect visible
                      }@

                      versus:
                      @dbTestGUI::~dbTestGUI()
                      {
                      QSqlDatabase db = QSqlDatabase().database();
                      qDebug() << db.isValid(); //returns true
                      db.close(); //connection disappears from server status
                      QSqlDatabase::removeDatabase(db.connectionName()); // sometimes some DLL's get unloaded, sometimest not.
                      //the following line appears on the console: "QSqlDatabasePrivate::removeDatabase: connection ‘qt_sql_default_connection’ is still in use, all queries will cease to work."
                      }@

                      When run the app, after executing this destructor it crashes. But when i comment the line:
                      @QSqlDatabase::removeDatabase(db.connectionName()); @

                      it doesn't

                      1 Reply Last reply
                      0
                      • M Offline
                        M Offline
                        michmu
                        wrote on last edited by
                        #11

                        So, to sum up - this is my destructor now:
                        @dbTestGUI::~dbTestGUI()
                        {
                        QSqlDatabase db = QSqlDatabase().database();
                        qDebug() << db.isValid();
                        db.close();
                        //QSqlDatabase::removeDatabase(db.connectionName()); //this line results in error after executing the d-tor
                        }@
                        when stepping out of it, I get the following message:

                        bq. Unable to free statement: connection pointer is NULL

                        So i guess, that Qt has a general problem with free'ing Prepared Statemets. Probably, because on one hand the QSqlQuery object is copied to the model (via QSqlQueryModel::setQuery), ant on the other hand ​QSqlQuery's parent is QSqlDatabase:
                        @QSqlQuery::​QSqlQuery(const QString & query = QString(), QSqlDatabase db = QSqlDatabase()) @

                        So instead of deallocating the query when the model is deleted - it is dealocated, when the database object gets destroyed.

                        1 Reply Last reply
                        0
                        • M Offline
                          M Offline
                          michmu
                          wrote on last edited by
                          #12

                          I guess I solved it. When the model is initialized as view's child:
                          @model = new QSqlQueryModel(this);@
                          The problem is order of operations. When I close the connection and remove the database in the destructor of my class - the database gets disconnected and no further operations are possible. But after my class' destructor, destructors of its base classes get into action - one by another, as ordered by inheritance. When Qobject::~Qobject() is executed, it gets to the
                          @QObjectPrivate::deleteChildren() @

                          method. And then, it finally gets to delete the model. The model wants to free the resources - which means QSqlResult (QPSQLResult to be specific in that case). This it how it looks:

                          @QPSQLResult::~QPSQLResult()
                          {
                          Q_D(QPSQLResult);
                          cleanup();

                          if (d->preparedQueriesEnabled && !d->preparedStmtId.isNull())
                              d->deallocatePreparedStmt();
                          

                          }@

                          So here Qt tries to deallocate preparedStatement - regardless of the fact, that the connection no longer exists:
                          @void QPSQLResultPrivate::deallocatePreparedStmt()
                          {
                          const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId;
                          PGresult *result = privDriver()->exec(stmt);

                          if (PQresultStatus(result) != PGRES_COMMAND_OK)
                              qWarning("Unable to free statement: %s", PQerrorMessage(privDriver()->connection));
                          PQclear(result);
                          preparedStmtId.clear();
                          

                          }@

                          So - to make it work properly, I wolud have to call
                          @QSqlQueryModel::~QSqlQueryModel() @

                          or
                          @QSqlQueryModel::clear()@

                          BEFORE closing the connection with the DB. I still think it's a bug.

                          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