QSqlDriver - misunderstandings?
-
Hi,
I have a strange behaviour. I compiled the Sqldriver for MariaDB and wrote a testapp, which works fine.
In my real app, I'm doing this:
In init() from MainWindow (called by singleshot timer 0):
db.setHostName(dbc.dbHost()); if (!db.open(dbc.dbUser(), dbc.dbPass())) throw new std::domain_error("can NOT connect to database"); if (!db.isDriverAvailable(dbc.driver())) throw new std::domain_error("db-driver not available!"); if (db.driver()->isOpenError()) throw new std::domain_error("db-driver has OPEN error!"); if (!db.driver()->isOpen()) throw new std::domain_error("db-driver not opened!"); Service::ValueManager().setValue("dbName", dbc.dbName());later during same init I use a loaded plugin to check and possibly setup the database.
First the check:QSqlDatabase db = QSqlDatabase::database(Service::ValueManager().getValue("dbName").toString()); QSqlQuery sql(db); int count = 0; try { bool rv = sql.exec("Select count(*) from SysEvents"); while (sql.next()) count = sql.value(0).toInt(); } catch (std::exception* e) { qDebug() << "failed to check database:" << e->what(); db.driver()->rollbackTransaction(); } catch (std::exception& e) { qDebug() << "failed to check database:" << e.what(); db.driver()->rollbackTransaction(); } return count > 0;No error, no exception. dbName is set and init function continues ...
Initially there's no table in the database, so count is 0.
I stepped through the code - no exception ...ValueManager manages ownerless properties used as global vars.
If above count is 0, table creation is initiated:
QSqlDatabase db = QSqlDatabase::database(Service::ValueManager().getValue("dbName").toString()); if (!db.isOpen()) throw new std::domain_error("database has NOT been opened!"); if (!db.driver()->isOpenError()) throw new std::domain_error("db-driver has OPEN error"); if (!db.driver()->isOpen()) throw new std::domain_error("db-driver not opened!"); if (!createTable(db)) throw new std::domain_error(QString("failed to create Table: %1") .arg(QSqlDatabase::database().driver()->lastError().text()).toStdString());This time, here in createTable function, db.driver()->isOpenError() is true, so an exception is thrown.
Obviously database-driver worked at begin of init-function, but error (may be wrong error message?) is active after selecting a non-existing table.
How can I reset such an error condition?
-
Check if Service::ValueManager().getValue("dbName").toString() really returns the same value everywhere, also look what db.hostName(), password() and others returns in the various functions.
btw: neither sql.exec() nor sql.next() throws an exception (but returns a bool which should be checked) so the try/catch block is useless.
-
@Christian-Ehrlicher said in QSqlDriver - misunderstandings?:
Check if Service::ValueManager().getValue("dbName").toString() really returns the same value everywhere, also look what db.hostName(), password() and others returns in the various functions.
I couldn't believe it, as I already have unittest to ensure proper work with multiple threads and this time its all in one thread.
any way ... I added some debug statements ...
check for existing data changed to:
QString dbName = Service::ValueManager().getValue("dbName").toString(); QSqlDatabase db = QSqlDatabase::database(dbName); QSqlQuery sql(db); int count = 0; qDebug() << "check: vm - dbName =" << dbName; qDebug() << "check: database name =" << db.databaseName(); if (!db.isOpen())... and this is the log output:
VM: new model created for > "dbName" < - value: [ QVariant(QString, "myDB") ] check: vm - dbName = "myDB" check: database name = "" -
Just to verify that network access to mariadb works, I changed connection.h from relationaltablemodel example to use network access of mariadb.
Then I adapted my database testproject:
#include <QCoreApplication> #include <QLocale> #include <QTranslator> #include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError> #include <QDebug> static void tellDrivers() { QStringList dl = QSqlDatabase::drivers(); for (int i=0; i < dl.size(); ++i) { qDebug() << "driver:" << dl.at(i) << "is" << (QSqlDatabase::isDriverAvailable(dl.at(i)) ? "available" : "NOT available"); } } static void connect() { QSqlDatabase db = QSqlDatabase::addDatabase("QMARIADB", "testDB"); db.setDatabaseName("testDB"); db.setHostName("netHost"); if (!db.open("testUser", "testPass")) { qDebug() << "failed to access database with:" << db.lastError(); } qDebug() << "opened database" << db.databaseName() << "with driver" << db.driverName(); } static void checkConnection() { QStringList sl = QSqlDatabase::connectionNames(); bool foundOpenDB = false; for (int i=0; i < sl.size(); ++i) { QSqlDatabase db = QSqlDatabase::database(sl.at(i), false); if (db.isOpen()) { qDebug() << "found open database:" << db.databaseName(); foundOpenDB = true; } } if (!foundOpenDB) qDebug() << "no opened database found!"; } static int getData() { QSqlDatabase db = QSqlDatabase::database("testDB"); if (!db.isOpen()) { qDebug() << "Database is NOT open :("; return 0; } QSqlQuery query(db); int count = 0; query.exec("SELECT * FROM person"); while (query.next()) { int id = query.value(0).toInt(); QString fname = query.value(1).toString(); QString lname = query.value(2).toString(); qDebug() << "\t" << id << fname << lname; ++count; } return count; } static void closeConnection() { QStringList sl = QSqlDatabase::connectionNames(); for (int i=0; i < sl.size(); ++i) { QSqlDatabase db = QSqlDatabase::database(sl.at(i), false); if (db.isOpen()) { qDebug() << "gonna close database:" << db.databaseName(); db.close(); } } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTranslator translator; const QStringList uiLanguages = QLocale::system().uiLanguages(); for (const QString &locale : uiLanguages) { const QString baseName = "DatabaseTest_" + QLocale(locale).name(); if (translator.load(":/i18n/" + baseName)) { a.installTranslator(&translator); break; } } tellDrivers(); qDebug() << "1"; connect(); qDebug() << "2"; checkConnection(); qDebug() << "3"; int rv = getData(); qDebug() << "4\tgot" << rv << "records"; closeConnection(); qDebug() << "5"; checkConnection(); qDebug() << "6"; return 0; }... and this is the Log-Output:
driver: "QMARIADB" is available driver: "QMYSQL" is available driver: "QPSQL" is available driver: "QODBC" is available driver: "QSQLITE" is available 1 opened database "testDB" with driver "QMARIADB" 2 found open database: "testDB" 3 101 "Danny" "Young" 102 "Christine" "Holand" 103 "Lars" "Gordon" 104 "Roberto" "Robitaille" 105 "Maria" "Papadopoulos" 4 got 5 records gonna close database: "testDB" 5 no opened database found! 6 -
So since your second app works you're doing something wrong in the other one. As I said you should print out some debug stuff everywhere you access Service::ValueManager().getValue("dbName").toString(); and getting the QSqlDatabase object afterwards to see if it's the same / if it is still open but you didn't until now.
-
Hi Christian,
@Christian-Ehrlicher said in QSqlDriver - misunderstandings?:
As I said you should print out some debug stuff everywhere you access Service::ValueManager().getValue("dbName").toString();
when you look at my post, I added some debug statements and posted the debug output:
@django-Reinhard said in QSqlDriver - misunderstandings?:
check for existing data changed to:
QString dbName = Service::ValueManager().getValue("dbName").toString();
QSqlDatabase db = QSqlDatabase::database(dbName);
QSqlQuery sql(db);
int count = 0;qDebug() << "check: vm - dbName =" << dbName;
qDebug() << "check: database name =" << db.databaseName();
if (!db.isOpen())... and this is the log output:
VM: new model created for > "dbName" < - value: [ QVariant(QString, "myDB") ]
check: vm - dbName = "myDB"
check: database name = ""So you can see, that the name from ValueManager is correct, but QSqlDatabase returns an empty name.
The only difference between working sample and failing app (as far as I know) is, that the working sample is one source file, whereas the failing app is an app + a dynamically loaded plugin.
It makes no difference, whether the code for connecting with user+password is from main-app or plugin. Connecting with user+password works, but reusing an open connection does not work.
Plugin-code is called from Main-thread and Mainwindow-init(). -
Please post a minimal, compilable example - I really don't know anymore where you added what and why. You posted a working solution so it must be a problem sonwehere in your code.