The main database object used throughout the program. More...
#include <Database.h>


Public Slots | |
| void | slot_queryThreadResult (QueryThreadCommand result) |
| void | pipe_queryResult (QSqlQuery *) |
Signals | |
| void | signal_queryQueue_changed (QueryQueue *queue) |
| void | tableChanged (const QString &tableName) |
Public Member Functions | |
| void | execThreaded (const QString &query, const QObject *sender) |
| void | execThreaded (const QueryThreadCommand &cmd) |
Static Public Member Functions | |
| static Database * | instance () |
| static QSqlDatabase | staticCon () |
| static QSqlQuery | execStatic (const QString &query=QString()) |
| static QSqlRecord | execStaticR (const QString &query) |
| static ProgressToolBar * | progressToolBar () |
| static bool | execPending (const QObject *sender) |
| static QSqlIndex | lastInserted (const QString &tableName) |
| static void | listenForTableChange (const QString &tableName) |
| static void | notifyTableChange (const QString &tableName) |
Protected Slots | |
| void | onDriverNotification (const QString &name) |
Protected Member Functions | |
| Database () | |
| Database (const QString &driver, const QString &dbName, const QString &host, const QString &user, const QString &passwd, int port) | |
| ~Database () | |
The main database object used throughout the program.
A cross-application notification system is implemented with NOTIFY. It could possibly be extended with a more generic database-centralized system.
| Database::Database | ( | ) | [protected] |
{
ConnectionDialog d;
if (d.exec() != QDialog::Accepted)
// temporary
threadSetup("QPSQL", "smartlet" , "pleco10.ugent.be", "smartlet", "hent", 5432);
else
threadSetup(d.driverName(), d.databaseName(), d.hostName(),
d.userName(), d.password(), d.port());
};
| Database::Database | ( | const QString & | driver, | |
| const QString & | dbName, | |||
| const QString & | host, | |||
| const QString & | user, | |||
| const QString & | passwd, | |||
| int | port | |||
| ) | [protected] |
{
threadSetup(driver, dbName, host, user, passwd, port);
}
| Database::~Database | ( | ) | [protected] |
| bool Database::execPending | ( | const QObject * | sender | ) | [static] |
This function should be (is?) treadsafe as it first checks the queue from which the threads take data, and then check the executing thread(s).
{
return Database::instance()->queryQueue.contains(QueryThreadCommand(const_cast<QObject*>(sender))) ||
Database::instance()->thread->currentCmd().sender() == sender;
}
Executes the query in the same thread the application is running.
Currently, there is no limit set on the duration of execution. This could be a problem in case of bad connection or connection drops. A solution to this problem could be a threaded execetution with a time limit. A possible implementation to start with is described here. Problem is that is such cases we would need to open a third connection because such connection could not be used in Database::staticCon() which is used in many models. A better approach would then probably be to use the existing QueryThread and implement some priority mechanism or similar? Check here for statement_timeout. This could be set dynamicaly each time on MainConnection, or it could be set once for max of 5 sec or similar. This should best be tested.
Referenced by BaseQueryModel::BaseQueryModel(), ProjectTreeModel::data(), execStaticR(), FilesUploadedModel::FilesUploadedModel(), notifyTableChange(), SensorUnitEditor::onAddButtonPress(), SqlDataStrategy::reconfigure(), ProjectTreeModel::removeRows(), CalibrationsModel::reQuery(), SensorUnitEditor::SensorUnitEditor(), ConvertableUnitModel::setConstraint(), SensorChannelModel::setConstraint(), SensorChannelCalibrationsView::setConstraint(), ProjectTreeModel::setData(), SqlUnitConvertor::SqlUnitConvertor(), TemplatesModel::TemplatesModel(), ConvertableUnitModel::unconstrain(), SensorChannelModel::unconstrain(), and UnitConversionEditor::UnitConversionEditor().
{
if (query.isNull() || query.isEmpty()) return QSqlQuery();
if (staticCon().isOpenError() || !staticCon().isOpen()){
qDebug() << "Static connection to database not open: can not execute query.";
return QSqlQuery();
}
//qDebug() << query;
static QSqlQuery q(staticCon());
if (q.exec(query)) return q;
else {
qWarning() << "Error from statically executed query: " << q.lastError().text()
<< "\nfrom query: " << query;
return q;
}
}
| QSqlRecord Database::execStaticR | ( | const QString & | query | ) | [static] |
Exectues a SELECT query and expects zero or one record to be returned.
This is mainly a convenience function for queries which fetch certain data from the database.
Referenced by lastInserted(), ProjectCalibrationEditor::onNewButtonPress(), SensorChannelCalibrationEditor::SensorChannelCalibrationEditor(), and MappedBaseEditor::setTable().
{
QSqlQuery q = execStatic(query);
// sanity checks
if (!q.isActive() || !q.isSelect()) {
if (!staticCon().isOpenError() && staticCon().isOpen())
qDebug() << "Query \"" << query << "\" retuned activestate: " << q.isActive() << " and selectstate: " << q.isSelect();
return QSqlRecord();
}
if (!(q.size() <= 1)){
qDebug() << "Query " << query << " returned " << q.size() << " rows where it only must return 0 or 1.";
Q_ASSERT(false);
}
if (q.size() == 0)
return QSqlRecord();
if (!q.next()) //position on valid record;
return QSqlRecord();
Q_ASSERT(q.isValid()); // true if the query is currently positioned on a valid record
// record ready and valid for return
return q.record();
}
Referenced by DatabaseAuditLogView::updateModel().
{
// setup command
QueryThreadCommand cmd(sender, query);
execThreaded(cmd);
}
| void Database::execThreaded | ( | const QueryThreadCommand & | cmd | ) |
{
Q_ASSERT(cmd.isValid());
// Check whether sender can receive the result: it needs an implementation
// of slot pipe_queryResult(QSqlQuery&)
if (cmd.sender()->metaObject()->indexOfSlot("pipe_queryResult(QSqlQuery*)") == -1) {
qWarning() << cmd.sender()->objectName() << " requested a threaded execution of query but has no pipe to fetch the result";
return;
}
// put command in queue
QueryQueue *queue = &queryQueue;
queue->enqueue(cmd);
// cancel any query currently in execution from m_sender
cancelQuery(cmd.sender());
// signal that queue has changed
emit signal_queryQueue_changed(queue);
}
| Database * Database::instance | ( | ) | [static] |
Referenced by execPending(), progressToolBar(), ProjectTreeModel::ProjectTreeModel(), SqlQueryModel::SqlQueryModel(), SqlTableModel::SqlTableModel(), staticCon(), and DatabaseAuditLogView::updateModel().
{
static Database db;
return &db;
};
Referenced by MappedBaseEditor::onSubmitButtonPress().
{
QSqlRecord result = Database::execStaticR("SELECT * FROM fnc_get_last_inserted_seq_id('" + tableName + "'::regclass)");
if (result.isEmpty() || result.isNull("column_name") || result.isNull("seq_number")) return QSqlIndex();
QSqlField field(result.value("column_name").toString(), QVariant::Int);
QSqlIndex index;
index.append(field);
index.setValue(0, result.value("seq_number"));
qDebug() << "returning last inserted id: " << index << " for table " << tableName;
return index;
}
| void Database::listenForTableChange | ( | const QString & | tableName | ) | [static] |
Sets the database driver to listen for table change notifications. If such change occurs, Database::tableChanged() is emitted.
Referenced by SqlHelper::setDependency().
{
if ((Database::staticCon().tables(QSql::AllTables).filter(QRegExp(".*" + tableName)).count() < 1) && (Database::staticCon().isOpen())){
qWarning() << "Trying to listen for table changes on " << tableName << ", but the table doesn't exist.";
}
// Setup notification
// Once made, this notification is never unsubscribed because it is
// unknown how many SqlTableModels there are based on the same table.
QString notificationName(GlobalConst::DB_TABLE_CHANGE_NOTIFY.arg(tableName));
if (!Database::staticCon().driver()->subscribedToNotifications().contains(notificationName))
Database::staticCon().driver()->subscribeToNotification(notificationName);
}
| void Database::notifyTableChange | ( | const QString & | tableName | ) | [static] |
This function is called by application objects to inform the Database and other concurrent applications that the application is finished changing/adjusting the table.
Referenced by MappedBaseEditor::onDeleteButtonPress(), TableBaseEditor::onSubmitButtonPress(), MappedBaseEditor::onSubmitButtonPress(), and ProjectTreeModel::setData().
{
QString notifyCmd("NOTIFY \"" + GlobalConst::DB_TABLE_CHANGE_NOTIFY.arg(tableName) + "\""); // " is mandatory because of Qt's specific LISTEN driver implementation
qDebug() << notifyCmd << " executed.";
execStatic(notifyCmd);
}
| void Database::onDriverNotification | ( | const QString & | name | ) | [protected, slot] |
{
qDebug() << name << QString(name).remove(GlobalConst::DB_TABLE_CHANGE_NOTIFY.arg(""));
if (name.contains(GlobalConst::DB_TABLE_CHANGE_NOTIFY.arg(""))){
QString tableName = QString(name).remove(GlobalConst::DB_TABLE_CHANGE_NOTIFY.arg(""));
emit tableChanged(tableName);
}
}
| void Database::pipe_queryResult | ( | QSqlQuery * | ) | [slot] |
{
Q_ASSERT_X(false, "Database", "unimplemented function Database::pipe_queryResult()");
}
| ProgressToolBar * Database::progressToolBar | ( | ) | [static] |
Referenced by main().
{
return Database::instance()->m_progressToolBar;
}
| void Database::signal_queryQueue_changed | ( | QueryQueue * | queue | ) | [signal] |
Referenced by execThreaded().
| void Database::slot_queryThreadResult | ( | QueryThreadCommand | result | ) | [slot] |
{
// Best would be to pass through the QSharedPointer<QSqlQuery> because the source might be deleted!
QMetaObject::invokeMethod(const_cast<QObject*>(result.sender()), "pipe_queryResult", Qt::DirectConnection, Q_ARG(QSqlQuery*, result.result()));
}
| QSqlDatabase Database::staticCon | ( | ) | [static] |
Referenced by MappedBaseEditor::addWidget(), DatabaseAuditLogView::DatabaseAuditLogView(), execStatic(), execStaticR(), listenForTableChange(), MappedBaseEditor::MappedBaseEditor(), PrivilegeEditor::PrivilegeEditor(), SqlQueryModel::reQuery(), TableBaseEditor::TableBaseEditor(), and TableEditor::TableEditor().
{
if (QSqlDatabase::connectionNames().isEmpty()) Database::instance(); //Moet, want Database kan anders nog niet geinitializeerd zijn.
QSqlDatabase db = QSqlDatabase::database("MainConnection", false);
Q_ASSERT(db.isValid());
if (db.isOpenError() || !db.isOpen())
return QSqlDatabase();
else
return db;
}
| void Database::tableChanged | ( | const QString & | tableName | ) | [signal] |
Referenced by onDriverNotification().
1.7.1