How to get data from intersystems cache db through ODBC? - c++

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);

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().

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

Qt 5.4, database not open error

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.

How can I get sqlite error code from Qt

I use sqlite database in my Qt program.
QSqlDatabase db;
db = QsqlDatabase::addDatabase("QSQLITE");
When I can not get data from sqlite db.lastError() function always return same thing
QSqlError(-1, "Driver not Loaded", "Driver not loaded")
How can I get sqlite error codes from Qt?
upd1:
QSqlQuery query;
query.exec(QString("select NAME from PEOPLE where AGE=%1").arg(age));
if(query.next())
{
}
else
{
//check for sqlite error
}
The best you can do with the Qt API itself is the following method:
int QSqlError::number() const
Returns the database-specific error number, or -1 if it cannot be determined.
See how the error codes from sqlite are handled in the driver codebase itself:
https://qt.gitorious.org/qt/qtbase/source/eb5c0f4b1266702c016b032e281bb92a3a642da6:src/sql/drivers/sqlite/qsql_sqlite.cpp#L324
You can see that the corresponding QSqlError constructor is used for that with passing the low-level error code to it as the last argument which you can obtain with the aforementioned method.
As you can see, it is not handling all the low-level errors similarly, but there is a default switch case in there for the rest. Even in the latter case, the errors are passed to the constructor.
You need to be aware of that, oftentimes, it cannot determine the exact low-level error in which case it will return -1 as per documentation.
Putting this into practice, you would be writing something like this:
QSqlQuery query;
query.exec(QString("select NAME from PEOPLE where AGE=%1").arg(age));
if (query.next())
{
} else {
qDebug() << "SqLite error:" << query.lastError().text() << ", SqLite error code:" << query.lastError().number();
}

Why can't I delete the SQLite database in Qt even after I call the database close function?

I'm writing a code to work with a SQLite database, all the code of the database works, but at end, when I try to delete the database, the database file is not deleted. I've called the close function, so why can't I delete the database?
The db.isOpen(); function returns false, and the QFile::remove(path); returns false too.
Note: On Windows Explorer i can delete the database only after closing the program window.
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
QString path = "path_to_db";
db.setDatabaseName(path);
if(db.open())
{
qDebug() << "Opened";
qDebug() << path;
}
else
{
qDebug() << db.lastError();
return a.exec();
}
QSqlQuery query(db);
//code to work with the database
db.close();
qDebug() << db.isOpen();
qDebug() << QFile::remove(path);
I found the solution, simply call query.clear(); before close the connection.