Is there any qt signal for sql database change? - c++

I wrote a C++ program using Qt. some variables inside my algorithm are changed outside of my program and in a web page. every time the user changes the variable values in the web page I modify a pre-created SQL database.
Now I want my code to change the variables value during run time without to stop the code. there is two options :
Every n seconds check the database and retrieve the variables value -> this is not good since I have to check if database content is changed every n seconds (it might be without any change for years. Also I don't want to check if the database content is changed)
Every time the database is changed my Qt program emits a signal so by catching this signal I can refresh the variables value, This seems an optimal solution and I want to write a code for this part
The C++ part of my code is:
void Update Database()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("Mydataset");
db.setUserName("user");
db.setPassword("pass");
if(!db.open())
{
qDebug()<<"Error is: "<<db.lastError();
qFatal("Failed To Connect");
}
QSqlQuery qry;
qry.exec("SELECT * from tblsystemoptions");
QSqlRecord rec = qry.record();
int cols = rec.count();
qry.next();
MCH = qry.value(0).toString(); //some global variables used in other functions
MCh = qry.value(1).toString();
// ... this goes on ...
}

QSqlDriver supports notifications which emit a signal when a specific event has occurred. To subscribe to an event just use QSqlDriver::subscribeToNotification( const QString & name ). When an event that you’re subscribing to is posted by the database the driver will emit the notification() signal and your application can take appropriate action.
db.driver()->subscribeToNotification("someEventId");
The message can be posted automatically from a trigger or a stored procedure. The message is very lightweight: nothing more than a string containing the name of the event that occurred.
You can connect the notification(const QString&)signal to your slot like:
QObject::connect(db.driver(), SIGNAL(notification(const QString&)), this, SLOT(refreshView()));
I should note that this feature is not supported by MySQL as it does not have an event posting mechanism.

There is no such thing. The Qt event loop and the database are not connected in any way. You only fetch/alter/delete/insert/... data and that's it. Option 1 is the one you have to do. There are ways to use TRIGGER on the server side to launch external scripts but this would not help you very much.

Related

How to start an immediate transaction of Sqlite in Qt?

Got troubles with using QSqlDatabase::transaction().
I want to start a transaction of Sqlite in Qt and I know this function : bool QSqlDatabase::transaction():
if(db.transaction())
{
QSqlQuery query(db);
// do stuff
if(!db.commit())
{
qDebug() << "Failed to commit";
db.rollback();
}
}
My problem is that I want to start an immediate transaction as follows:
> begin immediate;
> ...(operation)
> commit;
This function bool QSqlDatabase::transaction() will start a default transaction.
There will be several users using this program to access sqlite database so I need to control their access orders. If one user is writing, others can't read or write. It seems that I need to start an immediate transaction.
So how to start an immediate transaction by QSqlDatabase::transaction() ?
Is there way to specify transaction type in QSqlDatabase::transaction() ?
I use this to start an immediate transaction:
QsqlQuery query(myDatabase);
query.exec("begin immediate;");
query.exec(...) // read or write database.
query.exec("commit;");
It didn't work. There is still wrong data caused by multiple user access in database.

How to use Qt QSqlDriver::subscribeToNotification with SQLite3?

I'm writing a Qt application where different models can insert/delete/update the same table. When one model changes the database, I would like the other models to be notified of the change, so they can update their views accordingly.
It seems that the best way to monitor inserts, deletes and updates in SQLite is to use QSqlDriver::subscribeToNotification and then react to the notification signal. I know the syntax is along the lines of:
db.driver()->subscribeToNotification("anEventId");
However, I'm not sure what anEventId means. Is anEventId a constant provided by SQLite or do I code these specific events into SQLite using triggers or something else and then subscribe to them?
The subscribeToNotification implementation in the Qt sqlite driver relies upon the sqlite3_update_hook function of the sqlite C API. The Qt driver, however, is not forwarding the operation performed, just the table name, and that should be the misterious anEventId argument to pass to subscribeToNotification. In short, you can listen to events occurring in any table (given it is a rowid table, but it generally is) passing the table name to the subscribeToNotificationmethod. When your slot catches the notification signal, though, you only know that an operation occurred in that table, but (sadly) Qt won't tell you which one (INSERT, UPDATE, or DELETE).
So, given a QSqlDriver * driver:
driver->subscribeToNotification("mytable1");
driver->subscribeToNotification("mytable2");
driver->subscribeToNotification("mytable3");
then in your slot:
void MyClass::notificationSlot(const QString &name)
{
if(name == "mytable1")
{
// do something
}
else if(name == "mytable2")
{
//etc...

Can I use the same QSQLQuery variable to execute multiple statements?

Can I use the same QSQLQuery variable to execute multiple statements in Qt 5.3.2 using SQLite? Should I call the finish or the clear function after each execution?
For example:
QSqlQuery query;
query.prepare("INSERT INTO myTable (id, name) VALUES (:id, :name)");
query.bindValue(":id", id);
query.bindValue(":name", name);
if( !query.exec() )
{
qDebug() << "Error";
}
query.finish() // or query.clear()?
query.prepare("INSERT INTO myProducts (product, price) VALUES (:product, :price)");
query.bindValue(":product", product);
query.bindValue(":price", price);
if( !query.exec() )
{
qDebug() << "Error";
}
query.finish() // or query.clear()?
Note: I think I need to use the finish function, but I didn't understand exactly what the clear function does. The documentation says:
Clears the result set and releases any resources held by the query.
Sets the query state to inactive.
There is no need to use any of these functions in your case, you can do just fine without any of the two lines you are asking about
Can I use the same QSQLQuery variable to execute multiple statements in Qt 5.3.2 using SQLite?
Of course you can, but you are not obligated to do so. For example, If you wanted to perform an SQL query and it happens that you already have a valid QSqlQuery object around that you are finished with (you are not willing to fetch any more data from it), you can just use that same QSqlQuery object with your new query as there is no need to create another QSqlQuery.
Should I call the finish or the clear function after each execution?
Here is what the docs say about QSqlQuery::finish():
Instruct the database driver that no more data will be fetched from this query until it is re-executed. There is normally no need to call this function, but it may be helpful in order to free resources such as locks or cursors if you intend to re-use the query at a later time.
This means that you only need to use it if you want to keep a QSqlQuery object that you are finished with for a long time, in order to use it. But there is really no need to do so, just let your object go out of scope when you are finished with it.
And about QSqlQuery::clear():
Clears the result set and releases any resources held by the query. Sets the query state to inactive. You should rarely if ever need to call this function.
You can have a look at the Master Detail Example and in particular createConnection() function, to see how the same QSqlQuery object is used multiple times.

How to Disconnect all connected in QtScript

I use QtScript in my application. Scripts are written by users.
As example script like this:
//<init test time counters>
function testIteration() {
if (<test time is out>) {
myCppObject.mySignalAllDone.disconnect(testIteration);//disconnection
return;
}
//<Adding actions to myCppObject>
}
myCppObject.mySignalAllDone.connect(testIteration);//connection
testIteration();
I want from C++ stop this script before test time passed and write function like this
void MainWindow::toolButtonStopScript_clicked(){
disconnect(&this->myCppObject);// Disconnecting everything connected to myCppObject.
this->scriptEngineThread.abortAllEvaluations();
myCppObject.stopAllActivity();// emits mySignalAllDone, that is not disconnected (why and how to do that if I don't know what connections user made?), calling testIteration(), appending activity to myCppObject and this ends only when test time passed. How to solve this?
this->guiLog.log(GUILog::log_info, tr("Execution of script is interrupted by user"), this->logLevelMsgs);
this->connectMyCppObject();//make default connections
}
How to disconnect properly?
You can disconnect individual signals and slots:
disconnect(sender0, SIGNAL(overflow()),receiver1, SLOT(handleMathError()));
source: http://www.developer.nokia.com/Community/Wiki/Understanding_Signals_and_Slot_in_Qt
To get receivers, use QObject::receivers():
http://qt-project.org/doc/qt-4.8/qobject.html#receivers
It seems you cannot get slots (you must keep track of connections by yourself):
http://qt-project.org/forums/viewthread/6820
However, there are...
...Ways to debug signals and slots:
http://samdutton.wordpress.com/2008/10/03/debugging-signals-and-slots-in-qt/

SQLite database update in 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)