PDA

View Full Version : requested database does not belong to the calling thread



davidovv
13th December 2018, 15:42
I tried to compile my application for qt 5.12 and i get the error from title

QSqlDatabasePrivate::database: requested database does not belong to the calling thread.
The thing is that my application was already creating a new connection in every thread that uses database,
and i cloned default connection to a new one for the calling thread, like this:

QSqlDatabase db = QSqlDatabase::cloneDatabase(QSqlDatabase::database (), name);

With this new restriction I cant clone database from another thread. How am i supposed to do it now

ckvsoft
15th December 2018, 15:51
Hi

You can try my DataBaseManager

/*
* This file is part of QRK - Qt Registrier Kasse
*
* Copyright (C) 2015-2018 Christian Kvasny <chris@ckvsoft.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Button Design, and Idea for the Layout are lean out from LillePOS, Copyright 2010, Martin Koller, kollix@aon.at
*
*/

#ifndef DATABASEMANAGER_H
#define DATABASEMANAGER_H

#include "qrkcore_global.h"

#include <QMutex>
#include <QHash>
#include <QSqlDatabase>
#include <QMap>

class QThread;

class QRK_EXPORT DatabaseManager
{
public:
static QSqlDatabase database(const QString& connectionName = QLatin1String(QSqlDatabase::defaultConnection));
static void clear();
static void removeCurrentThread(QString);

private:
static QMutex s_databaseMutex;
static QMap<QString, QMap<QString, QSqlDatabase>> s_instances;

};

#endif // DATABASEMANAGER_H

databasemanager.cpp


/*
* This file is part of QRK - Qt Registrier Kasse
*
* Copyright (C) 2015-2018 Christian Kvasny <chris@ckvsoft.at>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Button Design, and Idea for the Layout are lean out from LillePOS, Copyright 2010, Martin Koller, kollix@aon.at
*
*/

#include "databasemanager.h"

#include <QSqlDatabase>
#include <QMutexLocker>
#include <QThread>
#include <QSqlError>
#include <QJsonObject>
#include <QDebug>

QMutex DatabaseManager::s_databaseMutex;
QMap<QString, QMap<QString, QSqlDatabase> > DatabaseManager::s_instances;

QSqlDatabase DatabaseManager::database(const QString& connectionName)
{
QMutexLocker locker(&s_databaseMutex);
QThread *thread = QThread::currentThread();

if (!thread->objectName().isEmpty()) {
QString objectname = QString::number((long long)QThread::currentThread(), 16);
// if we have a connection for this thread, return it
QMap<QString, QMap<QString, QSqlDatabase> >::Iterator it_thread = s_instances.find(objectname);
if (it_thread != s_instances.end()) {
QMap<QString, QSqlDatabase>::iterator it_conn = it_thread.value().find(connectionName);
if (it_conn != it_thread.value().end()) {
QSqlDatabase connection = it_conn.value();
qDebug() << "Function Name: " << Q_FUNC_INFO << " found SQL connection instances Thread: " << thread << " Name: " << connectionName;
if (connection.isValid())
return it_conn.value();
}
}
}

QString objectname = QString::number((long long)QThread::currentThread(), 16);

thread->setObjectName(objectname);
// otherwise, create a new connection for this thread

// cloneDatabase will not work with QT 5.11
/* QSqlDatabase connection = QSqlDatabase::cloneDatabase(
QSqlDatabase::database(connectionName),
QString("%1_%2").arg(connectionName).arg(objectname));
*/

QJsonObject connectionDefinition = Database::getConnectionDefinition();
QString dbtype = connectionDefinition.value("dbtype").toString();
QSqlDatabase connection = QSqlDatabase::addDatabase(dbtype, QString("%1_%2").arg(connectionName).arg(objectname));

if (dbtype == "QMYSQL") {
connection.setHostName(connectionDefinition.value("databasehost").toString());
connection.setUserName(connectionDefinition.value("databaseusername").toString());
connection.setPassword(connectionDefinition.value("databasepassword").toString());
connection.setConnectOptions(connectionDefinition. value("databaseoptions").toString());
}
connection.setDatabaseName(connectionDefinition.va lue("databasename").toString());

// open the database connection
// initialize the database connection
if (!connection.open()) {
// Todo: Exeption Handling
qCritical() << "Function Name: " << Q_FUNC_INFO << connection.lastError().text();
return connection;
}

qDebug() << "Function Name: " << Q_FUNC_INFO << " new SQL connection instances Thread: " << thread->currentThread() << " Name: " << connectionName;

s_instances[objectname][connectionName] = connection;
qDebug() << "Function Name: " << Q_FUNC_INFO << " connection instances used: " << s_instances.size();

return connection;
}

void DatabaseManager::clear()
{
s_instances.clear();
}

void DatabaseManager::removeCurrentThread(QString connectionName)
{
QString objectname = QString::number((long long)QThread::currentThread(), 16);
if (s_instances.contains(objectname)) {
QMap<QString, QSqlDatabase> map = s_instances.value(objectname);
QSqlDatabase connection = map.value(connectionName);
connection.close();
if (!connection.isOpen()) {
s_instances.remove(objectname);
qDebug() << "Function Name: " << Q_FUNC_INFO << " remove connection instance: " << objectname;
}
}

qDebug() << "Function Name: " << Q_FUNC_INFO << " connection instances used: " << s_instances.size();
}


lg chris

Udayagiri Rithwik
17th December 2018, 10:45
Close the connection to the database after each database operation or create one connection in the main thread

davidovv
23rd December 2018, 00:50
This was not logical restriction and i created a bug report at https://bugreports.qt.io
Bug is accepted and marked urgent/important. (QTBUG-72545), it was not inteded for cloneDatabase and it was as they say 'unwanted side effect'.
I hope it gets fixed with 5.12.1