SQLite database update in C++ - c++

I have an application where I show data from a database. In fact we can say it's a database editor.
Now I want to perform update/delete command on this opened database. Using the following commands, the database opens successfully.
int nRet = sqlite3_open(szFile, &mpDB);
From C# (.net api) I am able to update data from database
dbCmd5 = New SQLiteCommand(
"update Tbl_Tmp_Cal_Res Load_Time=5 WHERE Part_Index= 5", g_dbFlow);
dbCmd5.ExecuteNonQuery()
But from C++ I am getting error 5 (database is locked)
C++ code
int nRet = sqlite3_open(szFile, &mpDB);//database opened successfully.
sqlite3_exec(mpDB, "UPDATE query", 0, 0, &szError);//Error for this statement
Multithreading is not used in application.

Is the database used from another location in the code? Since something else clearly seems to have the database locked, I would guess that you're using the database from another location in the code and have forgotten to call sqlite3_finalize on a select statement or something similar.

maybe you have forgotten authentication step (username/password & etc)

Related

C++ Poco ODBC Transactions - AutoCommit mode

I am currently attempting to use transactions in my C++ app, but I have a problem with the ODBC's auto commit mode.
I am using the POCO libaries to create a connection to a PostgreSQL database on the same machine. Currently, I can send data to this database as single statements, but I cannot get my head around how to use Poco's transaction libraries to be able to send this data more quickly.
As I have several thousand records to insert, and so continuing to use single insert statements is extrememly slow and inpractical - So I am trying to use Poco's transaction to speed this up a bit (a fair bit).
The error I am encountering is a theoretically a simple one - Poco is throwing the following error:
'Invalid access: Session is in auto commit mode.'
I understand, as a result of this, I should somehow set "auto commit" to false - as it only allows me to commit data to the database line by line, rather than as a single transaction.
The problem is how I set this.
Currently, I have a session created from Session.h, that looks alot like this:
session = new Poco::Data::Session(
"ODBC",
connection_data.str()
);
Where connection data is a simple stringstream with the login information, password, database, server and "Driver={PostgreSQL ANSI};" to tell ODBC to utilize PostgreSQL's driver.
I have tried just setting a property "autocommit" to false through the session's setFeature or setProperty settings, this, of course, was to no avail. (it was more of a ditch attempt at this point).
session->setFeature("AUTOCOMMIT", false);
Looking around, I saw a possible alternative method by creating a ODBC sessionImpl directly from ODBC/session/SessionImpl.h instead of using this generic method above, and then creating a new session object from this.
The benefits of this are that ODBC's sessionImpl has references to autocommit mode in the header, which would suggest it would be able to handle this:
void autoCommit(const std::string&, bool val);
/// Sets autocommit property for the session.
However, having not used sessionImpl before, I cannot garuntee if this will work or if can can get this to work with the limited documentation available.
I am using C++ 03 (Not 11), with Visual Studio 2015
Poco 1.7.5
Boost (Where needed)
Would any one know the correct way of setting this feature (above) or a alternative method to achieving this?
edit: Looking at the source of poco, at:
https://github.com/pocoproject/poco/blob/develop/Data/ODBC/src/SessionImpl.cpp#L153
The property seems be named autoCommit, and looking at
https://github.com/pocoproject/poco/blob/develop/Data/include/Poco/Data/AbstractSessionImpl.h#L120
the case of the property names seem to matter. So, does it help if you use session->setFeature("autoCommit", false);?
Cant you just call session->begin(); and session->end(); on the corresponding Session object?
What is returned by session->canTransact()?
According to the doc begin() will start a new transaction, the doc does not mention any property that needs to be set before or after.
See: https://pocoproject.org/docs/Poco.Data.Session.html
Also faced a similar issue.
First of all before begin() need:
m_ses.setFeature("autoCommit", false);
m_ses.begin();
And the second issue is that this feature stays "autoCommit" in false for all other sessions. So don't forget for the next session call
session.setFeature("autoCommit", true);

How to check if file is appropriated with database driver in Qt

Assuming I want to open a connection to SQLite3 database in Qt. It will be connected to an existed database dbName.
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
Now I need to set db.setDatabaseName(dbName), where dbName is received through a QFileDialog.
However, as long as dbName is a valid file name, then db.open() is always true. Is there anyway to check if the file dbName is a SQLite3 database, but not of any other type? What I can do now is to execute a query and check for error like:
db.setDatabaseName(dbName);
if (db.open()) {
QSqlQuery qr(db);
if (!qr.exec(".database;")) {
qDebug() << qr.lastError().text();
return false;
}
}
but it won't work if the file is empty.
Qt always uses the SQLITE_OPEN_CREATE flag, so nonexistent or empty files are considered valid (for a new, empty database).
If you don't want to change Qt, or write your own database driver, the only alternative is to manually check for a valid database header in the file.
I had to face the same problem.
In fact, there is two issues :
1/ As CL said, Qt always uses the SQLITE_OPEN_CREATE flag, so if you try to open a database that point to a non-existent file, the database will be created and you get a success.
You can adress this issue by checking if the file exists before open (see QFile::Exists static method)
2/ SQLite use "lazy initialization", so until you make a request on the database, the file is not really opened.
You can adress this issue by executing a simple request right after the database open, and check the result.
If you don't know anything in advance about the database schema, you can try to read one of the "PRAGMA" values : http://www.sqlite.org/pragma.html#pragma_table_info

QtSql connection

I am trying to create a connection to a database and insert/delete/make queries to the database. I know SQL relatively well but I cannot seem to wrap my head around it in Qt. I used to program in Delphi.
This is my code so far:
QSqlDatabase db;
db.addDatabase("QSQLITE");
db.setHostName( "localhost" ); //I don't know if i should include this the database is in the same directory as my program
db.setDatabaseName( "Xmato.odb" );
db.setUserName( "" ); //There is no username
db.setPassword( "" ); //There is no password
db.open();
db.prepare("SELECT * FROM Members");
db.exec();
I have added this to my .pro file:
QT += sql;
An included QtSql to my main file.
When I run this code I get the error:
QSqlQuery::prepare: database not open
Any ideas will me much appreciated.
P.S.: I use c++ on Linux Ubuntu 12.04 and used LibreOffice Base to create my database.
After a bit of google-ing - openoffice libre's internal database is using HSQLDB (natural choice for Java). Here's a small discussion about HSQLDB.
It appears that some versions of openlibre base is also able to connect to external databases. I would recommend setting up something that is more accessible to C++, specifically Qt.
Only a few drivers like ODBC & SQLite is included by default.
Which means that depending on the database being used, one may need to get additional source code (or packages) and compile a plugin/dll/so. The library is loaded dynamically (i.e. run-time) by the QtSql module. I've run into this for mysql drivers.
When you get all of that setup, your call to addDatabase should match the kind of database you're using.
QSqlDatabase::addDatabase( "QODBC" ); // For something like MSSQL
QSqlDatabase::addDatabase( "QSQLITE" ); // For SQLite
QSqlDatabase::addDatabase( "QMYSQL" ); // For MySQL
Personally, if you're just doing this for kicks, a quick and easy database is SQLITE. You can even download plugins/extensions for Mozilla Firefox that will offer you a GUI to the database.
Driver not loaded
you need the QSQLITE driver.
db.drivers() returns a list of all the available database drivers.
In Ubuntu 12.04 the driver for sqlite is in a package named libqt4-sql-sqlite.
But: is odb a sqlite database??
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName( "Xmato.odb" );
if (db.open())
{
QSqlQuery query(db); // if multiple connections used, without the `db` in constructor will cause the query to use the default database (first opened and available one)
query.exec("select * from members");
}
should do the same. username and password are not needed and since it is a file, you just have to use setDatabaseName to set what file you want to open.

Do I need an SQL server to work with Qt's QtSql library?

I am a beginner with Qt, so my question might be a bit basic.
My intention is to work with an ODBC database located in my hard drive. I have tried to open it with this code:
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setHostName("");
db.setDatabaseName("c:\\database.mdb");
bool ok = db.open();
QSqlQuery query;
query.exec("SELECT name FROM results WHERE tag>10");
while (query.next()) {
QString name1 = query.value(0).toString();
qDebug() << name1;
}
Now, the problem is that the program can't find the database, failing at the db.open() line. I suspect that Qt can't open a database directly, but instead has to deal with an SQL server. Is this so? If that's the case, I'd be grateful if you could give me some clues on how to go ahead, particularly regarding host name (is it localhost?).
Also, I am not sure of whether the path to the file must be included in DatabaseName.
PS: I have no problem shifting to a different kind of database/server, e.g. MySQL. So if your solution requires this, I'd be happy with it!
Thanks in advance
D
Unless you specifically need a Jet/MS Access format database for something else you'd be better off going with SQLite. Qt has SQLite support built-in (QSQLITE driver) - you just point it at the database file and go. No need to setup ODBC data sources or anything.
According to the documentation, you should set the setDatabaseName to the ODBC datasource. You then configure the ODBC datasource to point to the appropriate file.
For future reference:
Just as Werne Strydom said, the argument of setDatabaseName is not the database file name, but the name of the ODBC datasource that points to your database. Therefore, you need to create an ODBC that points to your database.
The usual way to do this (in Windows) would be to go to Control Panel\System & security\Administrative tools\Data Sources (ODBC). But if you're in a 64-bit machine and want to work with a 32-bit driver, go instead to C:\windows\SysWOW64 and run odbcad32.exe
When you do this, a dialog opens (same dialog regardless of 64/32-bits). Here you create your ODBC, give it a name and link it to your actual database. In my case, as I am working with a local database, I used the "User DNS" tab.
Then, back in Qt, you put that ODBC name as argument for setDatabaseName. And it works! (Or it did for me...)
The new bit of code looks like:
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setHostName("localhost");
db.setDatabaseName("MyDataSource");
bool ok = db.open();
QSqlQuery query;
query.exec("SELECT name FROM results WHERE tag>10");
while (query.next()) {
QString name1 = query.value(0).toString();
qDebug() << name1;
}
where "MyDataSource" is the name I gave to the ODCB.

QT SQLite not working in Embedded device

I am using QT framework. Basically I am creating application for ARM devices.
Now I've created sample application using SQLite for DB work. Thing is that one is working in my desktop but when I cross compiled it for device and tried to execute it in my device Getting error.
So I logged some error messages. Finally i found that DB file was created successfully but unable to create table in device.
Is it because of out of memory issue?
Code :
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("songs.db");
if (!db.open()) {
QMessageBox::critical(0, qApp->tr("Cannot open database"),
qApp->tr("Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information how "
"to build it.\n\n"
"Click Cancel to exit."), QMessageBox::Cancel);
//return false;
debugLog("#fileListThread::run()-> Unable to establish a database connection.."<<db.lastError(););
}
else
{
debugLog("#fileListThread::run()-> opened songs.db successfully..");
}
QSqlQuery query;
bool queryStatus = query.exec("create table songsList (id int primary key, "
"Song varchar(20), Artist varchar(20),Producer varchar(20))");
if(queryStatus)
{
debugLog("#fileListThread::run()-> created table in songs DB successfully..");
}
else
{
debugLog("#fileListThread::run()-> failed to create table in songs DB.."<<query.lastError(););
}
Okay! One more quick question-> Is it possible to create DB file and executing queries inside in embeedded devices. In my device available free memory is 9MB.
Thanks,
Vishnu
I think you should use
CREATE TABLE IF NOT EXISTS songsList
sql statement rather than
create table songsList
Otherwise once the table is created , the second time you try to execute it, you may get an error.
Other than that I don't see a problem but who knows... I hope this helps.