Qt 5.4, database not open error - c++

I'm new to C++/Qt and am trying to write to a SQLite database that I have created in the root directory of my project.
Here is one of the many sites I've been using for reference:
http://www.java2s.com/Code/Cpp/Qt/ConnecttoSqliteanddoinsertdeleteupdateandselect.htm
I created a function that receives an argument of all the user entered values as an object. I would like to write these values that the user entered into my root directory database.
Here is the function that takes the database object and attempts to write them into my root level database "matrixics.db".
My Function:
#include <QtSql>
#include <QSqlDatabase>
#include <QtDebug>
#include <QFile>
#include <QMessageBox>
void db_connection::writeDBValues(db_config *dbInfo)
{
//connect to matrixics.db
QSqlDatabase matrixics = QSqlDatabase::addDatabase("QSQLITE", "MatrixICS");
//using absolute path doesn't work either
//matrixics.setDatabaseName("D:/Qt Projects/build-MatrixICS-Desktop_Qt_5_4_0_MinGW_32bit-Debug/matrixics.db");
matrixics.setDatabaseName("./matrixics.db");
if(!QFile::exists("./matrixics.db"))
{
QString failedMsg = tr("FAILED: Could not locate matrixics.db file");
QMessageBox::warning(this, tr("ERROR: Failed MatrixICS Database Connection!"), failedMsg);
}
else if (!matrixics.open())
{
QString failedMsg = tr("FAILED: ") + matrixics.lastError().text();
QMessageBox::warning(this, tr("ERROR: Failed to open matrixics.db!"), failedMsg);
}
else
{
//write db values
QSqlQuery qry;
if (m_connectionName == "localDb")
{
qry.prepare( "INSERT INTO settings (local_db_type, local_db_host, local_db_port, local_db_user, local_db_pass) VALUES (?, ?, ?, ?, ?)" );
}
else if (m_connectionName == "remoteDb")
{
qry.prepare( "INSERT INTO settings (remote_db_type, remote_db_host, remote_db_port, remote_db_user, remote_db_pass) VALUES (?, ?, ?, ?, ?)" );
}
//bind all values
qry.addBindValue(dbInfo->m_db_type);
qry.addBindValue(dbInfo->m_hostname);
qry.addBindValue(dbInfo->m_port);
qry.addBindValue(dbInfo->m_db_user);
//encode user pass
//base64_encode is included in a globals.h fn not shown above
QString encodedPass = base64_encode(dbInfo->m_db_pass);
qry.addBindValue(encodedPass);
if(!qry.exec()) qDebug() << qry.lastError();
matrixics.close();
}
QSqlDatabase::removeDatabase("MatrixICS");
}
The Error:
QSqlQuery::prepare: database not open
QSqlError("", "Driver not loaded", "Driver not loaded")
QSqlDatabasePrivate::removeDatabase: connection 'MatrixICS' is still in use, all queries will cease to work.
My Question:
How is it possible for the script to make it down to the QSqlQuery::prepare function without the database being open? I would think that when I perform if (!matrixics.open()) the script would throw my "Failed to open" message if the database was not open. However, it is not, so logic should dictate that the database is in fact open, yet I receive QSqlQuery::prepare: database not open.

Your QSqlQuery object must be constructed with a reference to the QSqlDatabase. In other words, make that line
QSqlQuery qry(matrixics);
See QSqlQuery::QSqlQuery documentation.

Related

QT open not existing database

I've created simple function for connecting with sqlite3 database. But I've recognized that it makes connection , even if database file not exist
As you can see below : I've tried to check if file really exist and if it's really connected .
bool DatabaseConnection::make_connection(const QString &path)
{
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
#ifdef QT_DEBUG
qDebug() << "File: '" + db.databaseName() + "' exist = " << QFileInfo::exists(db.databaseName());
qDebug() << db.isValid();
#endif
if (!db.open())
{
QMessageBox::critical(nullptr,
QObject::tr("Error - Cannot open database"),
QObject::tr("Failed attempt to establish connection \n"),
QMessageBox::Close);
return false;
}
qDebug() <<"Open:" <<db.isOpen();
qDebug() << "errors:" << db.isOpenError();
return true;
}
after changing path name on first compilation - file not exist , but connection seems to be established (True).
In next compilation tells that file exist ( I've couldn't find it anywhere) , and again connection is 'established'
I had similar problem, db.open() creates new file if it doesn't exist.
Just wrap db.open() arround QFileInfo::exists(path).
I believe if you attempt to access an SQLite3 database that does not exist, it will create one. So db.open() will attempt to create a database file if one is not found. You would be best served checking if the DB file exists first using some other method before calling db.open().

Open and closing ODBC connections causing crashes

I wrote a program that used a SQLite database and it worked correctly. Now I'm trying to make it work with SQL Server. The application crashes on startup and I have worked out that it's to do with the way I am opening and closing database connections. I'm really unsure if I need to open the connection only once or if should I open and close it each time I run a query? Also is it advised to delete the pointer to the query after it executes? Removing the conn.connOpen and conn.connClose sections makes the program run, but its unstable.
Any advice on how to handle connections (since I have a lot of buttons that execute different queries) is greatly appreciated.
My connection string is stored in a header (mainwindow)
// mainwindows.h
public:
QSqlDatabase mydb;
void connClose()
{
connected = false;
mydb.close();
mydb.QSqlDatabase();
mydb.removeDatabase(QSqlDatabase::defaultConnection);
}
bool connOpen()
{
if( !connected )
{
mydb = QSqlDatabase::addDatabase("QODBC"); //uses dsn, connects fine.
mydb.setDatabaseName("Test");
if(!mydb.open())
{
qDebug() << mydb.lastError().text();
connected = false;
}
else
{
qDebug()<<"Connected";
connected = true;
}
}
return connected;
}
private:
static bool connected;
Here is an example of how I'm calling queries in my .cpp files;
Financelog::Financelog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Financelog)
{
ui->setupUi(this);
setWindowFlags( windowFlags() | Qt::WindowMinimizeButtonHint |
Qt::WindowContextHelpButtonHint | Qt::WindowMinMaxButtonsHint );
MainWindow conn; // call the connection string
if(!conn.connOpen())
ui->label_sec_status->setText("<font color='red'>Failed to Open Database</font>");
else
ui->label_sec_status->setText("<font color='green'>Connected</font>");
QSqlQueryModel * modal=new QSqlQueryModel();
conn.connOpen(); // ---- **DO I NEED THIS? REMOVING STOPS CRASHES.**
QSqlQuery* qry=new QSqlQuery(conn.mydb);
qry->prepare("select DEAL_DATE, DEAL_NUMB, CCICOMM, CCIPREM, INCOME from LOG");
qry->exec();
modal->setQuery(*qry);
ui->tableView->setModel(modal);
ui->tableView->resizeColumnsToContents();
ui->tableView->setAlternatingRowColors(true);
ui->tableView->setStyleSheet("alternate-background-color: #009900; background-color: #006600;");
//delete qry; **DO I NEED THIS TO RELEASE MEMORY?**
conn.connClose(); // **DO I NEED THIS?**
qDebug() << (modal->rowCount());
}
You should only open the connection once, and keep it open while using it. Not open and close for every query.
If you have long phases of nothing between 2 queries, you can use a QTimer to close the connection after beeing unused for a "long" time (e.g. 5 min). Do so if you see the connection timing out. But by default, not needed.
QSqlQuery, just like QSqlDatabase should be used as "value class", not as a pointer (See Qt Documentation). Instead of creating one with new, create it on the stack. Queries are copyable.
Code sample:
//only once, i.e. in your windows constructor
conn.connOpen();
//set up the model
QSqlQueryModel * modal=new QSqlQueryModel();
QSqlQuery qry(conn.mydb);
qry.prepare("...");
qry.exec();
modal->setQuery(qry);
//...
// do not delete the query or close the database connection!
qDebug() << (modal->rowCount());
You can close the connection in the destructor after the model has been destroyed:
model->deleteLater();
conn.connClose();

How to deploy Qt application with an existing Sqlite db?

I want to package my Qt application with an existing Sqlite db. I have the standard Qt database code:
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setDatabaseName("database.sqlite");
bool connected = m_db.open();
if (!connected) {
qDebug() << "Error: connection with database failed";
} else {
qDebug() << "Database: connection success";
QSqlQuery q(m_db);
q.prepare("SELECT * FROM people");
if (q.exec()) {
qDebug() << "Yay!";
} else {
qWarning() << "Bad exec: " << q.lastError();
qWarning() << q.executedQuery();
}
}
However, the result is:
Error: connection with database failed
I know this is because it's not finding the correct database, and is instead creating a new one. If I provide the absolute path on my development machine to m_db.setDatabaseName(), it works. But my database file is in my .qrc and will not be available in that location when I deploy... so how can I get a reliable path for this database?
in the setDatabaseName-call use the right syntax for resource files:
m_db.setDatabaseName(":database.sqlite"); // <-- note the : before the name
... presuming the database file is located in the root of your resource file system.
Greetings, Thomas

How to get data from intersystems cache db through ODBC?

This is how i try to get a data from db:
#include <QCoreApplication>
#include <QtCore>
#include <QtSql>
#include "iostream"
int main(int argc, char *argv[])
{
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setDatabaseName("DRIVER={InterSystems ODBC};SERVER=localhost;PORT=1972;DATABASE=USER;UID=_system;PWD=SYS; Unicode SQLTypes=1;");
if (!db.open())
{
std::cout << "Error opening database" << std::endl;
return -1;
}
else
{
QSqlQuery query;
if(query.exec("SELECT * FROM ACCOUNTS")){
std::cout << "Select succses!" << std::endl;
}
while (query.next())
{
std::cout << "Getting results..." << std::endl;
std::cout << query.value(0).toString().toStdString() << std::endl;
}
std::cout << "EXIT!" << std::endl;
return 0;
}
}
And after query.exec(...) query.next() is always false but I really know that there is a data in the table. This behavior reproduce in the case when I try to get data from sample tables of Cache DB. What did i do wrong?
Thanks for your help.
The problem was that connection config is wrong:
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setDatabaseName("DRIVER={InterSystems ODBC};SERVER=localhost;PORT=1972;DATABASE=USER;UID=_system;PWD=SYS; Unicode SQLTypes=1;");
it should be:
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC3");
db.setDatabaseName("DRIVER={InterSystems ODBC35};SERVER=localhost;PORT=1972;DATABASE=USER;UID=_system;PWD=SYS; Unicode SQLTypes=1;");
[as I said in the comments, I'm not familiar with this API Just looking through the documentation as I answer]
the documentation for the constructor of QSqlQuery
Constructs a QSqlQuery object using the SQL query and the database db.
If db is not specified, or is invalid, the application's default
database is used. If query is not an empty string, it will be
executed.
This means your query is opened on the default database (whatever that means).
Looking at the QSqlDatabase documentation:
QSqlDatabase also supports the concept of a default connection, which
is the unnamed connection. To create the default connection, don't
pass the connection name argument when you call addDatabase().
however, you're giving a name argument in your addDatabase():
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
... that means it is not the default connection.
My guess is that you should either:
QSqlDatabase db = QSqlDatabase::addDatabase();
or
QSqlQuery query=QSqlQuery(db);

PostgreSQL opening other database failed

Well, the problem is, when I close previous database and try to connect to the new one I get this:
Connection failed!
unterminated quoted string in connection info string
QPSQL:Unable to connect
Here full description of what I'am doing:
First I logging in with any avalible login and connect to the default "posgtres" database. Then I executing query select * from pg_database; to get list of all avalible databases. After that I close database.
void FdbToPg::connectToDatabase(){
database.setHostName(ui.lineIP->text());
database.setDatabaseName("postgres");
database.setUserName(ui.lineLogin->text());
database.setPassword(ui.linePassword->text());
database.setPort(ui.linePort->text().toInt());
QSqlQuery query;
if(database.open()){
QString dbOutput = "select * from pg_database;";
query.exec(dbOutput);
while(query.next()){
ui.comboBox->addItem(query.value(0).toString(),QVariant::Char);
}
database.close();
}else{
QMessageBox::information(this, "Error", "Cant' connect ot the database");
}
}
Then when on of the avalible databases been choosed I trying to connect to it. And there I get that error message
void FdbToPg::on_selectButton_clicked(){
database.setDatabaseName(ui.comboBox->itemData(ui.comboBox->currentIndex()).toString());
database.setHostName(ui.lineIP->text());
database.setUserName(ui.lineLogin->text());
database.setPassword(ui.linePassword->text());
database.setPort(ui.linePort->text().toInt());
bool ok = database.open();
if(ok != true){
QMessageBox::information(this, "Connection", "Connection failed! \n" + database.lastError().text());
} else {
QMessageBox::information(this, "Connection", "Connection worked!");
}
}
What's wrong here and how I properly suppose to close old database and open new one?
Well, the problem were here
database.setDatabaseName(ui.comboBox->itemData(ui.comboBox->currentIndex()).toString());
ui.comboBox->itemData(ui.comboBox->currentIndex()).toString() were return an empty string. I changed it to database.setDatabaseName(ui.comboBox->currentIndex()); and now it's ok.
But I still don't understand whats wrong with
ui.comboBox->itemData(ui.comboBox->currentIndex()).toString() command