Qsqlite duplicate connection warning in qt c++ - c++

I am creating an application in qt which uses sqlite database. I have written a class to open database connection. The constructor for the class is given below:
currencydb::currencydb()
{
currency = QSqlDatabase::addDatabase("QSQLITE");
currency.setDatabaseName("currency.sqlite");
if(!currency.isOpen())
{
if (!currency.open())
{
qDebug() << "Error: connection with database fail";
}
else
{
qDebug() << "Database currency: connection ok";
}
}
}
Since i use this constructor, when i create object for the database class, i get following warning:
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
Is there a way to check whether the database is already open?

That warning doesn't mean that your database is already open but that you already have a connection to the database with a default name. The connection provides access to the database via (in your case SQLITE v3) database driver. You create a default connection to the database when you don't pass the connection name argument when you call static public method QSqlDatabase::addDatabase().
You can use QSqlDatabase::contains() for checking if you already have the default connection.
CurrencyDb::CurrencyDb()
{
currency = openDb("QSQLITE", "currency.sqlite");
}
QSqlDatabase CurrencyDb::openDb(const QString &driver, const QString &name) const
{
QSqlDatabase db;
// contains() default argument is initialized to default connection
if (QSqlDatabase::contains())
{
db = QSqlDatabase::database(QLatin1String(QSqlDatabase::defaultConnection), false);
}
else
{
db = QSqlDatabase::addDatabase(driver.toUpper());
}
db.setDatabaseName(name);
if (!db.isValid())
{
// Log error (last error: db.lastError().text()) and throw exception
}
if (!db.open())
{
// Log error (last error: db.lastError().text()) and throw exception
}
return db;
}

Related

Why QSqlDatabase object won't work if addDatabase method assigned later?

This won't work:
{
QSqlDatabase db;
db.addDatabase("QSQLITE", "manDb");
QString path = QDir::currentPath()+"/"+"Sqlite.db";
db.setDatabaseName(path);
if(db.open())
{
qDebug()<< "Database Created successfully...";
}else{
qDebug()<< "Failed to create Database...";
}
}
QSqlDatabase::removeDatabase("manDb");
Output: Failed to create Database...
But this works:
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "manDb");
QString path = QDir::currentPath()+"/"+"Sqlite.db";
db.setDatabaseName(path);
if(db.open())
{
qDebug()<< "Database Created successfully...";
}else{
qDebug()<< "sucessfully Failed to create Database...";
}
}
QSqlDatabase::removeDatabase("manDb");
Output: Database Created successfully...
Why?
Your first code sample does not work because according to documentation
QSqlDatabase db;
Creates an empty, invalid QSqlDatabase object. Use addDatabase(), removeDatabase(), and database() to get valid QSqlDatabase objects.
Then you try to call static QSqlDatabase::addDatabase method with db.addDatabase("QSQLITE", "manDb"); which returns QSqlDatabase class instance, but you do not assign it's return value to variable to use it later.
Adds a database to the list of database connections using the driver type and the connection name connectionName. If there already exists a database connection called connectionName, that connection is removed.
The database connection is referred to by connectionName. The newly
added database connection is returned.
So, in the first sample you tried to use QSqlDatabase in wrong way. Meanhile your second sample is a correct usage.

connection 'qt_sql_default_connection' is still in use, all queries will cease to work

I've made separate functions for open and close connection.But it wont let me to add new record on new form.
this is login header file.
public:
QSqlDatabase mydb;
void connClose()
{
//QString connection;
//connection = mydb.connectionName();
mydb.close();
//mydb.removeDatabase(connection);
mydb.removeDatabase(mydb.connectionName());
}
bool connOpen()
{
mydb=QSqlDatabase::addDatabase("QSQLITE");
mydb.setDatabaseName("./Poem.db");
if(mydb.open())
{
return true;
}
else if(!mydb.open())
{
return false;
}
}
this is the other form add button :
QString Title,Group,Poem;
Title = ui->lineEdit->text();
Group = ui->label_2->text();
Poem = ui->textEdit->toPlainText();
MainWindow mainwindow;
mainwindow.connOpen();
QSqlQuery * qry1 = new QSqlQuery(mainwindow.mydb);
qry1->prepare("insert into Poems(Title,Poem,Group) values ('"+Title+"','"+Poem+"','"+Group+"')");
if(qry1->exec())
{
QMessageBox::critical(this,tr("درج شعر جدید"),tr("شعر اضافه شد"));
mainwindow.connClose();
}
I get this errors :
duplicate connection name 'qt_sql_default_connection', old connection removed.
connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
You are committing exactly what Qt QSqlDatabase Documentation warns about:
Warning: There should be no open queries on the database connection
when this function is called
...
// WRONG
QSqlDatabase db = QSqlDatabase::database("sales");
QSqlQuery query("SELECT NAME, DOB FROM EMPLOYEES", db);
QSqlDatabase::removeDatabase("sales"); // will output a warning
// "db" is now a dangling invalid database connection, // "query"
contains an invalid result set
and the correct is:
{
QSqlDatabase db = QSqlDatabase::database("sales");
QSqlQuery query("SELECT NAME, DOB FROM EMPLOYEES", db);
}
// Both "db" and "query" are destroyed because they are out of scope
QSqlDatabase::removeDatabase("sales"); // correct
So in your case you execute query qry1 and remove the database within same scope (i.e before qry1 goes out of scope), you should modify your code to make sure qry1 is executed and gets destroyed / goes out of scope / before deleting the database. Try this:
{
QSqlQuery * qry1 = new QSqlQuery(mainwindow.mydb);
qry1->prepare("insert into Poems(Title,Poem,Group) values ('"+Title+"','"+Poem+"','"+Group+"')");
if(qry1->exec())
{
QMessageBox::critical(this,tr("درج شعر جدید"),tr("شعر اضافه شد"));
}
}
mainwindow.connClose();

QSqlDatabase can't be removed - Queries still active

I started with c++ QT recently.
I created class "ControllerOfDB" to hold pointer to my QSqlDatabase and few functions (to make inserts/selects).
Example select function:
QList<data1> GetData1()
{
QList<data1> output;
if(!dataBase->isOpen())
dataBase->open();
if(dataBase->isOpen())
{
QSqlQuery* query = new QSqlQuery(*dataBase);
query->prepare("SELECT * FROM table1");
if(query->exec())
while (query->next())
{
output.append( *(new data1(
query->value(0).toInt(),
query->value(1).toString(),
query->value(2).toInt(),
query->value(3).toInt(),
query->value(4).toInt(),
)) );
}
query->clear();
query->finish();
delete query;
}
return output;
}
It was all working fine, until i had to add possibility to change db or login as different user. I modified Connect and Disconnect function. After few iterrations, this is what i get:
void Connect()
{
dataBase = new QSqlDatabase(QSqlDatabase::addDatabase("QPSQL", "Main"));
dataBase->setHostName(hostName);
dataBase->setPort(port);
dataBase->setDatabaseName(dbName);
dataBase->setUserName(userName);
dataBase->setPassword(userPass);
if(!dataBase->isOpen())
dataBase->open();
}
void Disconnect()
{
if(dataBase != NULL)
if(dataBase->isOpen()){
dataBase->close();
dataBase->removeDatabase("Main");
dataBase = NULL;
}
}
hostName, port, dbName, userName and userPass are also attributes of that class.
public:
QSqlDatabase *dataBase;
QString hostName;
int port;
QString dbName;
QString userName;
QString userPass;
whenever i try to diconnect and create new connection i recieve warnings/errors about queries of my current connections - even if i only "connected" ( = used function Connect() ).
I already saw few similar topics and documentation for it, saying i have to remove queries from scope, but at this point i don't know how.
when you look at QSqlDatabase document, the method removeDatabase is static, so your method Disconnect logic should be like:
void Disconnect()
{
if(dataBase != NULL) {
if(dataBase->isOpen()){
dataBase->close();
}
delete dataBase;
dataBase = NULL;
}
QSqlDatabase::removeDatabase("Main");
}

Copy tables between sqlite databases, qt, causes error

I want to write the contents of my SQlite database on user click to another SQlite database. For this I am trying to make connections to two databases and do select query from one db and in transaction do insert query to another. But I gets error on connection creation itself.
In header file:
private:
QSqlDatabase database;
QSqlDatabase mHistoryDB;
In source file:
qDebug() << Q_FUNC_INFO << "Invoked";
database = QSqlDatabase::addDatabase("QSQLITE");
mHistoryDB = QSqlDatabase::addDatabase("QSQLITE");
#ifdef Q_OS_WIN
database.setDatabaseName("C:/ANDROID_DATABASE/RestPos.sqlite");
mHistoryDB.setDatabaseName("C:/ANDROID_DATABASE/History/RestPos.sqlite");
#else
database.setDatabaseName("/mnt/sdcard/pos/RestPos.sqlite");
mHistoryDB.setDatabaseName("/mnt/sdcard/pos/History/RestPos.sqlite");
#endif
While running I gets the following error:
QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work.
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
If I use only database connection there occurs no error. I am not sure how to do copy with single connection.
My current copy code is as below:
bool readStatus = false,
writeStatus = false;
if (database.isOpen() && mHistoryDB.open())
{
QSqlQuery readQuery (database);
QSqlQuery writeQuery(mHistoryDB);
readStatus
= readQuery.exec("SELECT costcentre_id, bill_no, bill_date "
"FROM BillHdr");
qDebug() << Q_FUNC_INFO << getLastExecutedQuery(readQuery);
if (readStatus)
{
mHistoryDB.transaction();
writeQuery.prepare("INSERT INTO BillHdr "
"(costcentre_id, bill_no, bill_date) "
"VALUES (:costcentre_id, :bill_no, :bill_date)");
while(readQuery.next())
{
if (readQuery.isValid())
{
BillHeader billHdr;
billHdr.costCenterId = readQuery.value(0).toString();
billHdr.billNumber = readQuery.value(1).toDouble();
billHdr.date = readQuery.value(2).toDate();
writeQuery.bindValue(":costcentre_id", billHdr.costCenterId);
writeQuery.bindValue(":bill_no", billHdr.billNumber);
writeQuery.bindValue(":bill_date", billHdr.date);
writeStatus = writeQuery.exec();
qDebug() << Q_FUNC_INFO << getLastExecutedQuery(writeQuery);
if (!writeStatus)
{
qDebug() << Q_FUNC_INFO << "error in write" <<
writeQuery.lastError().text();
mHistoryDB.rollback();
mHistoryDB.close();
break;
}
}
}
writeStatus = mHistoryDB.commit();
qDebug() << Q_FUNC_INFO << "commit:" << writeStatus;
if (!writeStatus)
{
mHistoryDB.rollback();
}
mHistoryDB.close();
}
}
qDebug() << Q_FUNC_INFO << "Exits" << writeStatus;
return writeStatus;
We can read from the Qt documentation about QSqlDatabase :
Warning: If you add a connection with the same name as an existing connection, the new connection replaces the old one. If you call this
function more than once without specifying connectionName, the default
connection will be the one replaced.
So when you add a database multiple times within a specific name or without specifying any (default connection), the connection is replaced and that warning appears.
you should call QSqlDatabase::addDatabase() once for each of the databases with different connection names :
database = QSqlDatabase::addDatabase("QSQLITE", "database_Connection");
mHistoryDB = QSqlDatabase::addDatabase("QSQLITE", "mHistoryDB_Connection");

Handling QSqlDatabase connections

What is the correct way to handle connections for QSqlDatabase?
In my program I am doing it this way:
DatabaseConnector *databaseConnector = 0;
try
{
databaseConnector = new DatabaseConnector();
//Do stuff...
delete databaseConnector;
}
catch(QString e)
{
delete databaseConnector;
QMessageBox::information(this,"Error",e);
}
databaseConnector.h
#ifndef DATABASECONNECTOR_H
#define DATABASECONNECTOR_H
#include <QtSql>
class DatabaseConnector
{
public:
DatabaseConnector();
DatabaseConnector(QString hostname, QString database, QString user, QString password);
~DatabaseConnector();
private:
QSqlDatabase db;
};
#endif // DATABASECONNECTOR_H
databaseconnector.cpp
#include "databaseconnector.h"
#include <QString>
DatabaseConnector::DatabaseConnector()
{
QSettings settings;
db = QSqlDatabase::addDatabase("QIBASE");
db.setHostName(settings.value("db/host").toString());
db.setDatabaseName(settings.value("db/name").toString());
db.setUserName(settings.value("db/user").toString());
db.setPassword(settings.value("db/pass").toString());
if(!db.open())
{
QString databaseConnectionError = db.lastError().text();
throw databaseConnectionError;
}
}
DatabaseConnector::DatabaseConnector(QString hostname, QString database, QString user, QString password)
{
db = QSqlDatabase::addDatabase("QIBASE");
db.setHostName(hostname);
db.setDatabaseName(database);
db.setUserName(user);
db.setPassword(password);
if(!db.open())
{
QString databaseConnectionError = db.lastError().text();
throw databaseConnectionError;
}
}
DatabaseConnector::~DatabaseConnector()
{
db.close();
}
I'm getting error even if I use QSqlDatabase::removeDatabase(db.connectionName());
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
Normally you don’t need to open the database connection more than once within your application.
When adding a database, you can name the connection :
QSqlDatabase::addDatabase( "QIBASE", "MyDBConnectionName" );
You can use the name to query for the connection :
if( QSqlDatabase::contains( "MyDBConnectionName" ) )
{
QSqlDatabase db = QSqlDatabase::database( "MyDBConnectionName" );
//Do stuff...
}
else
{
// connection not found, do something
}
Also notice that before calling QSqlDatabase::removeDatabase you should disconnect your database :
db.close();
QSqlDatabase::removeDatabase("MyDBConnectionName");
In order to add a new database, you need to give it a name. If you do not give a unique name, the default database is re-used. This is documented in the class reference.
Try:
db = QSqlDatabase::addDatabase("QIBASE", databaseName);
In main app:
QSqlDatabase db =QSqlDatabase::addDatabase( "QSQLITE");
in second app:
QSqlDatabase db2 =QSqlDatabase::database();