Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 1

Qt-interest Archive, December 2007
Unable to remove database ?

Pages: Prev | 1 | 2 | Next

Message 16 in thread

Stephen Collyer wrote:
> Bill KING wrote:
>
>   
>> Lastly, if you keep a QSqlDatabase object local to your class, then
>> yeah, unless you assign to it an empty QSqlDatabase() object, there'll
>> be a second reference still alive. (eg, db = QSqlDatabase(); should be 
>> enough to clear out the reference to remove the warning).
>>     
>
> Bill
>
> Can you expand on this ? At what point are you suggesting that
> this assignment be done ? In a ctor, before the run() method
> does the same thing, I guess ?
>
>   
You had a class local QSqlDatabase object. That's fine and well, so long
as you clear it out before unregistering it. Otherwise it'll keep a
reference hanging around and fire off the warning. So, just before you
unregister, set the QSqlDatabase member variable to what is effectively
a null sqldatabase object, and everything works as it's supposed to.
Does that help a little? (I'm not sure I'm explaining it well enough,
but I'm having trouble finding the words at the moment to describe
what's happening).

-- 
 [ signature omitted ] 

Message 17 in thread

Bill KING wrote:

> You had a class local QSqlDatabase object. That's fine and well, so long
> as you clear it out before unregistering it. Otherwise it'll keep a
> reference hanging around and fire off the warning. So, just before you
> unregister, set the QSqlDatabase member variable to what is effectively
> a null sqldatabase object, and everything works as it's supposed to.
> Does that help a little? (I'm not sure I'm explaining it well enough,
> but I'm having trouble finding the words at the moment to describe
> what's happening).

OK, I can confirm that this solves that problem. However,
it feels like a workaround to a problem that shouldn't be
there in the first place. Is this "hanging reference" thing
considered to be a bug, and likely to be fixed in the future ?

-- 
 [ signature omitted ] 

Message 18 in thread

Stephen Collyer wrote:

>> You had a class local QSqlDatabase object. That's fine and well, so long
>> as you clear it out before unregistering it. Otherwise it'll keep a
>> reference hanging around and fire off the warning. So, just before you
>> unregister, set the QSqlDatabase member variable to what is effectively
>> a null sqldatabase object, and everything works as it's supposed to.
>> Does that help a little? (I'm not sure I'm explaining it well enough,
>> but I'm having trouble finding the words at the moment to describe
>> what's happening).
> 
> OK, I can confirm that this solves that problem. However,
> it feels like a workaround to a problem that shouldn't be
> there in the first place. Is this "hanging reference" thing
> considered to be a bug, and likely to be fixed in the future ?
> 

It's not a bug and it's not likely to be changed.

You create a QSqlDatabase object and then you remove its underlying 
database connection. You keep the QSqlDatabase object, but what good is 
it with the connection gone? That's why the warning is fired - to warn 
you that the object you're keeping is unusable.

You don't really need to keep it around anyhow. Just use 
QSqlDatabase::database() whenever you need it and then let it run out of 
scope.


--
 [ signature omitted ] 

Message 19 in thread

Anders Larsen wrote:

> You create a QSqlDatabase object and then you remove its underlying
> database connection. You keep the QSqlDatabase object, but what good is
> it with the connection gone? That's why the warning is fired - to warn
> you that the object you're keeping is unusable.
> 
> You don't really need to keep it around anyhow. Just use
> QSqlDatabase::database() whenever you need it and then let it run out of
> scope.

OK, I've reimplemented the logic following this suggestion
and can confirm that it works. Now I create the QSqlDatabase
object in the run() method of a thread like this:


QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", tname);
db.setDatabaseName(dbname);
db.setUserName(username);
db.setPassword(password);

if (! db.open())
{
    throw std::runtime_error(qPrintable("Failed to open MySQL database "
                                        + dbname));
}

and remove it in a dtor like this:

QSqlDatabase::database(tname).close();
QSqlDatabase::removeDatabase(tname);

In between, whenever I need the connection, I get
it via something like:

QSqlDatabase db = QSqlDatabase::database(connection_name);

I prefer this approach to Bill's suggestion for two reasons.

1) I don't keep a QSqlDatabase object hanging around in my
objects; I merely call on the awesome puissance of Qt to
give it to me when I need it. That removes a data member.

2) It eliminates the need for the odd-looking assignment
to remove the hanging reference.

-- 
 [ signature omitted ] 

Message 20 in thread

On Wednesday 12 December 2007 15:11:50 Stephen Collyer wrote:
You might want to check the performance of that approach. If you're openeing a 
database connection each time you need it, for example to hit the database 
with a sql statement, this might degrade performance quite a bit. 
I've not looked at the sources for this one, but if the open actually creates 
a database connection, you'll suffer from having to connect to the database 
each time: this is usuallly a relatively slow and expensive operation.

Happy coding,
Eric
> Anders Larsen wrote:
> > You create a QSqlDatabase object and then you remove its underlying
> > database connection. You keep the QSqlDatabase object, but what good is
> > it with the connection gone? That's why the warning is fired - to warn
> > you that the object you're keeping is unusable.
> >
> > You don't really need to keep it around anyhow. Just use
> > QSqlDatabase::database() whenever you need it and then let it run out of
> > scope.
>
> OK, I've reimplemented the logic following this suggestion
> and can confirm that it works. Now I create the QSqlDatabase
> object in the run() method of a thread like this:
>
>
> QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", tname);
> db.setDatabaseName(dbname);
> db.setUserName(username);
> db.setPassword(password);
>
> if (! db.open())
> {
>     throw std::runtime_error(qPrintable("Failed to open MySQL database "
>                                         + dbname));
> }
>
> and remove it in a dtor like this:
>
> QSqlDatabase::database(tname).close();
> QSqlDatabase::removeDatabase(tname);
>
> In between, whenever I need the connection, I get
> it via something like:
>
> QSqlDatabase db = QSqlDatabase::database(connection_name);
>
> I prefer this approach to Bill's suggestion for two reasons.
>
> 1) I don't keep a QSqlDatabase object hanging around in my
> objects; I merely call on the awesome puissance of Qt to
> give it to me when I need it. That removes a data member.
>
> 2) It eliminates the need for the odd-looking assignment
> to remove the hanging reference.


--
 [ signature omitted ] 

Message 21 in thread

Eric Methorst wrote:
> On Wednesday 12 December 2007 15:11:50 Stephen Collyer wrote:
> You might want to check the performance of that approach. If you're openeing a 
> database connection each time you need it, for example to hit the database 
> with a sql statement, this might degrade performance quite a bit. 

I'm not. The db is opened at the start of a thread, in its run() method.
That happens once (per thread), to a named connection. I then retrieve
that named connection as required by calling SqlDatabase::database(name)
but that doesn't reopen the connection.

-- 
 [ signature omitted ] 

Message 22 in thread

On Thursday 13 December 2007 00:05:17 Stephen Collyer wrote:
> Eric Methorst wrote:
> > On Wednesday 12 December 2007 15:11:50 Stephen Collyer wrote:
> > You might want to check the performance of that approach. If you're
> > openeing a database connection each time you need it, for example to hit
> > the database with a sql statement, this might degrade performance quite a
> > bit.
>
> I'm not. The db is opened at the start of a thread, in its run() method.
> That happens once (per thread), to a named connection. I then retrieve
> that named connection as required by calling SqlDatabase::database(name)
> but that doesn't reopen the connection.
Better check again. I looked at the ultimate documentation (read the source 
code) and in the  QSqlDatabase's destructor the 'close()' is called when it 
is the last one (it uses a refcount.
I did not follow up that particular function, but it seems rather obvious for 
me. Also, the database() call has a paramer called 'open', which will open 
the connection for you if it's closed.
In other words, if you create add the connection, then always create a new 
QSqlDatabase object, do your query and let the DB object go out of scope, the 
database connection will always be closed and reopened once you ask for it 
again! (As long as you have no other database connection still open)
so you might want to benchmark this

{
QSqlDatabase db = QSqlDatabase::database("mydbd");
for (int i = 0; i < 1000; ++i){

	QSqlQuery qry = "SELECT count(*) from SomeTable;
	qry.execute();
}
}

agains this:
for (int i = 0; i < 1000; ++i){
	QSqlDatabase db = QSqlDatabase::database("mydbd");
	QSqlQuery qry = "SELECT count(*) from SomeTable;
	qry.execute();
}

(ok, don't pin me down on the query syntax here: I'm sure you get the meaning)
The second one should be significantly slower. If you can test it: try having 
the database on another computer.


--
 [ signature omitted ] 

Message 23 in thread

Eric Methorst wrote:

>> I'm not. The db is opened at the start of a thread, in its run() method.
>> That happens once (per thread), to a named connection. I then retrieve
>> that named connection as required by calling SqlDatabase::database(name)
>> but that doesn't reopen the connection.
> Better check again. I looked at the ultimate documentation (read the source 
> code) and in the  QSqlDatabase's destructor the 'close()' is called when it 
> is the last one (it uses a refcount.
> I did not follow up that particular function, but it seems rather obvious for 
> me. Also, the database() call has a paramer called 'open', which will open 
> the connection for you if it's closed.

Right. QSqlDatabase::database() only attempts to reopen the connection
when you explicitly ask it to. I'm not asking it to, so it will
merely return the connection in its current state, open or closed.
My code is working fine, so I'm pretty certain that the connection
does remain open, once it is opened, using the technique I described.

The code for QSqlDatabase::database looks like this:

QSqlDatabase QSqlDatabasePrivate::database(const QString& name, bool open)
{
    const QConnectionDict *dict = dbDict();
    Q_ASSERT(dict);

    dict->lock.lockForRead();
    QSqlDatabase db = dict->value(name);
    dict->lock.unlock();
    if (db.isValid() && !db.isOpen() && open) {
        db.open();
        if (!db.isOpen())
            qWarning("QSqlDatabasePrivate::database: unable to open
database: %s",
                     db.lastError().text().toLocal8Bit().data());

    }
    return db;
}

db.open() can only be called when the open argument is supplied.
If you don't request that it be opened explicitly, it won't
be opened.

> In other words, if you create add the connection, then always create a new 
> QSqlDatabase object, do your query and let the DB object go out of scope, the 
> database connection will always be closed and reopened once you ask for it 
> again! 

I think the code above indicates that that is not the case.

-- 
 [ signature omitted ] 

Message 24 in thread

On Friday 14 December 2007 11:08:08 Stephen Collyer wrote:
<SNIP />
> db.open() can only be called when the open argument is supplied.
> If you don't request that it be opened explicitly, it won't
> be opened.
I see. But how do you keep your connection open? It should be closed after all 
if the last of your QSqlDatabase objects goes out of scope. (as far as I can 
judge from the desctructor on that class, anyway)
>
>
> I think the code above indicates that that is not the case.


--
 [ signature omitted ] 

Message 25 in thread

Eric Methorst wrote:

> I see. But how do you keep your connection open? It should be closed after all 
> if the last of your QSqlDatabase objects goes out of scope. (as far as I can 
> judge from the desctructor on that class, anyway)

Qt keeps an object internally. The destructor won't close the connection 
until all objects - including the internal one - are gone.

The internal object is removed when you call removeDatabase().


--
 [ signature omitted ] 

Message 26 in thread

On Monday 17 December 2007 10:09:21 Anders Larsen wrote:
> Eric Methorst wrote:
> > I see. But how do you keep your connection open? It should be closed
> > after all if the last of your QSqlDatabase objects goes out of scope. (as
> > far as I can judge from the desctructor on that class, anyway)
>
> Qt keeps an object internally. The destructor won't close the connection
> until all objects - including the internal one - are gone.
>
> The internal object is removed when you call removeDatabase().
Ah, thanks for the info.
Would have been nice if that bit had been a a bit more obvious in the help :)
>
>
> --
> Anders L.
>
> --
> To unsubscribe - send a mail to qt-interest-request@xxxxxxxxxxxxx with
> "unsubscribe" in the subject or the body. List archive and information:
> http://lists.trolltech.com/qt-interest/


--
 [ signature omitted ]