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