QT -= gui
QT += network sql script
+
include(core.pri)
include(target.pri)
+
+RESOURCES *= ../../src/core/sql.qrc
include(monolithic.pri)
include(target.pri)
+
RESOURCES *= ../../src/icons/icons.qrc
+RESOURCES *= ../../src/core/sql.qrc
chatwidget state
make signalproxy threadsafe
utf-8 / encodings
+ externalize SQL-queries, provide migration path...
Showstoppers:
=============
switch to network-IDs -> ?
remove buffergroups (DB) -> ?
insert buffertype field rein (DB) -> ?
- externalize SQL-queries, provide migration path... -> EgS
core-user admin, rights management (ACL) -> Sput?
BUG: multi-user join -> ?
#include "settings.h"
-Settings::Settings(QString g, QString applicationName) : QSettings(QCoreApplication::organizationName(), applicationName), group(g) {
+Settings::Settings(QString g, QString applicationName)
+
+#ifdef Q_WS_MAC
+ : QSettings(QCoreApplication::organizationDomain(), applicationName),
+#else
+ : QSettings(QCoreApplication::organizationName(), applicationName),
+#endif
+ group(g)
+{
/* we need to call the constructor immediately in order to set the path...
#ifndef Q_WS_QWS
--- /dev/null
+DELETE FROM backlog
+WHERE bufferid IN (SELECT DISTINCT bufferid FROM buffer WHERE userid = :userid)
--- /dev/null
+DELETE FROM buffer
+WHERE userid = :userid
--- /dev/null
+DELETE FROM network
+WHERE userid = :userid
--- /dev/null
+DELETE FROM quasseluser
+WHERE userid = :userid
--- /dev/null
+INSERT INTO buffer (userid, networkid, buffername)
+VALUES (:userid, (SELECT networkid FROM network WHERE networkname = :networkname AND userid = :userid2), :buffername)
--- /dev/null
+INSERT INTO backlog (time, bufferid, type, flags, senderid, message)
+VALUES (:time, :bufferid, :type, :flags, (SELECT senderid FROM sender WHERE sender = :sender), :message)
--- /dev/null
+INSERT INTO network (userid, networkname)
+VALUES (:userid, :networkname)
--- /dev/null
+INSERT INTO quasseluser (username, password)
+VALUES (:username, :password)
\ No newline at end of file
--- /dev/null
+INSERT INTO sender (sender)
+VALUES (:sender)
\ No newline at end of file
--- /dev/null
+SELECT userid
+FROM quasseluser
+WHERE username = :username AND password = :password
--- /dev/null
+SELECT bufferid
+FROM buffer
+JOIN network ON buffer.networkid = network.networkid
+WHERE network.networkname = :networkname AND network.userid = :userid AND buffer.userid = :userid2 AND lower(buffer.buffername) = lower(:buffername)
--- /dev/null
+SELECT DISTINCT buffer.bufferid, buffername, network.networkid, networkname
+FROM buffer
+JOIN network ON buffer.networkid = network.networkid
+JOIN backlog ON buffer.bufferid = backlog.bufferid
+WHERE buffer.userid = :userid AND time >= :time
--- /dev/null
+SELECT messageid FROM backlog
+WHERE time = :time AND bufferid = :bufferid AND type = :type AND senderid = (SELECT senderid FROM sender WHERE sender = :sender)
--- /dev/null
+SELECT messageid, time, type, flags, sender, message, displayname
+FROM backlog
+JOIN buffer ON backlog.bufferid = buffer.bufferid
+JOIN sender ON backlog.senderid = sender.senderid
+LEFT JOIN buffergroup ON buffer.groupid = buffergroup.groupid
+WHERE (buffer.bufferid = :bufferid OR buffer.groupid = (SELECT groupid FROM buffer WHERE bufferid = :bufferid2)) AND backlog.messageid >= :firstmsg AND backlog.messageid <= :lastmsg
+ORDER BY messageid DESC
--- /dev/null
+SELECT messageid, time, type, flags, sender, message, displayname
+FROM backlog
+JOIN buffer ON backlog.bufferid = buffer.bufferid
+JOIN sender ON backlog.senderid = sender.senderid
+LEFT JOIN buffergroup ON buffer.groupid = buffergroup.groupid
+WHERE buffer.bufferid = :bufferid OR buffer.groupid = (SELECT groupid FROM buffer WHERE bufferid = :bufferid2)
+ORDER BY messageid DESC
+LIMIT :limit OFFSET :offset
--- /dev/null
+SELECT count(*)
+FROM backlog
+WHERE bufferid = :bufferid AND messageid < :messageid
--- /dev/null
+SELECT messageid, time, type, flags, sender, message, displayname
+FROM backlog
+JOIN buffer ON backlog.bufferid = buffer.bufferid
+JOIN sender ON backlog.senderid = sender.senderid
+LEFT JOIN buffergroup ON buffer.groupid = buffergroup.groupid
+WHERE (buffer.bufferid = :bufferid OR buffer.groupid = (SELECT groupid FROM buffer WHERE bufferid = :bufferid2)) AND backlog.time >= :since
+ORDER BY messageid DESC
+LIMIT -1 OFFSET :offset
--- /dev/null
+SELECT count(*)
+FROM backlog
+WHERE bufferid = :bufferid AND time >= :since
--- /dev/null
+SELECT userid
+FROM quasseluser
+WHERE username = :username
--- /dev/null
+CREATE TABLE quasseluser (
+ userid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ username TEXT UNIQUE NOT NULL,
+ password BLOB NOT NULL)
+
+
--- /dev/null
+CREATE TABLE sender (
+ senderid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ sender TEXT UNIQUE NOT NULL)
+
+
--- /dev/null
+CREATE TABLE network (
+ networkid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ userid INTEGER NOT NULL,
+ networkname TEXT NOT NULL,
+ UNIQUE (userid, networkname))
--- /dev/null
+CREATE TABLE buffer (
+ bufferid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ userid INTEGER NOT NULL,
+ groupid INTEGER,
+ networkid INTEGER NOT NULL,
+ buffername TEXT NOT NULL)
--- /dev/null
+CREATE UNIQUE INDEX buffer_idx
+ ON buffer(userid, networkid, buffername)
--- /dev/null
+CREATE TABLE backlog (
+ messageid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ time INTEGER NOT NULL,
+ bufferid INTEGER NOT NULL,
+ type INTEGER NOT NULL,
+ flags INTEGER NOT NULL,
+ senderid INTEGER NOT NULL,
+ message TEXT)
--- /dev/null
+CREATE TABLE coreinfo (
+ key TEXT NOT NULL PRIMARY KEY,
+ value TEXT)
--- /dev/null
+INSERT INTO coreinfo (key, value) VALUES ('schemaversion', '1')
--- /dev/null
+UPDATE quasseluser
+SET username = :username
+WHERE userid = :userid
--- /dev/null
+UPDATE quasseluser
+SET password = :password
+WHERE userid = :userid
--- /dev/null
+DROP TABLE coreinfo
--- /dev/null
+CREATE TABLE coreinfo (
+ key TEXT NOT NULL PRIMARY KEY,
+ value TEXT)
--- /dev/null
+INSERT INTO coreinfo (key, value) VALUES ('schemaversion', '1')
--- /dev/null
+#!/bin/bash
+
+cat > sql.qrc <<EOF
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+EOF
+find . -name \*.sql -exec echo " <file>{}</file>" \; >> sql.qrc
+cat >> sql.qrc <<EOF
+</qresource>
+</RCC>
+EOF
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-07 by the Quassel IRC Team *
+ * devel@quassel-irc.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) version 3. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "abstractsqlstorage.h"
+
+#include <QSqlError>
+#include <QSqlQuery>
+
+AbstractSqlStorage::AbstractSqlStorage(QObject *parent)
+ : Storage(parent),
+ _schemaVersion(0)
+{
+}
+
+AbstractSqlStorage::~AbstractSqlStorage() {
+ {
+ QSqlDatabase db = QSqlDatabase::database("quassel_connection");
+ db.commit();
+ db.close();
+ }
+ QSqlDatabase::removeDatabase("quassel_connection");
+}
+
+QSqlDatabase AbstractSqlStorage::logDb() {
+ QSqlDatabase db = QSqlDatabase::database("quassel_connection");
+ if(db.isValid() && db.isOpen())
+ return db;
+
+ if(!openDb()) {
+ qWarning() << "Unable to Open Database" << engineName();
+ qWarning() << " -" << db.lastError().text();
+ }
+
+ return QSqlDatabase::database("quassel_connection");
+}
+
+bool AbstractSqlStorage::openDb() {
+ QSqlDatabase db = QSqlDatabase::database("quassel_connection");
+ if(db.isValid() && !db.isOpen())
+ return db.open();
+
+ db = QSqlDatabase::addDatabase(driverName(), "quassel_connection");
+ db.setDatabaseName(databaseName());
+
+ if(!hostName().isEmpty())
+ db.setHostName(hostName());
+
+ if(!userName().isEmpty()) {
+ db.setUserName(userName());
+ db.setPassword(password());
+ }
+
+ return db.open();
+}
+
+bool AbstractSqlStorage::init(const QVariantMap &settings) {
+ Q_UNUSED(settings)
+ QSqlDatabase db = logDb();
+ if(!db.isValid() || !db.isOpen())
+ return false;
+
+ if(installedSchemaVersion() == -1) {
+ qDebug() << "Storage Schema is missing!";
+ return false;
+ }
+
+ if(installedSchemaVersion() > schemaVersion()) {
+ qWarning() << "Installed Schema is newer then any known Version.";
+ return false;
+ }
+
+ if(installedSchemaVersion() < schemaVersion()) {
+ qWarning() << "Installed Schema is not up to date. Upgrading...";
+ if(!upgradeDb())
+ return false;
+ }
+
+ qDebug() << "Storage Backend is ready. Quassel Schema Version:" << installedSchemaVersion();
+ return true;
+}
+
+QString AbstractSqlStorage::queryString(const QString &queryName, int version) {
+ if(version == 0)
+ version = schemaVersion();
+
+ QFileInfo queryInfo(QString(":/SQL/%1/%2/%3.sql").arg(engineName()).arg(version).arg(queryName));
+ if(!queryInfo.exists() || !queryInfo.isFile() || !queryInfo.isReadable()) {
+ qWarning() << "Unable to read SQL-Query" << queryName << "for Engine" << engineName();
+ return QString();
+ }
+
+ QFile queryFile(queryInfo.filePath());
+ if(!queryFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return QString();
+ QString query = QTextStream(&queryFile).readAll();
+ queryFile.close();
+
+ return query.trimmed();
+}
+
+QString AbstractSqlStorage::queryString(const QString &queryName) {
+ return queryString(queryName, 0);
+}
+
+QSqlQuery *AbstractSqlStorage::cachedQuery(const QString &queryName, int version) {
+ QPair<QString, int> queryId = qMakePair(queryName, version);
+ if(!_queryCache.contains(queryId)) {
+ QSqlQuery *query = new QSqlQuery(logDb());
+ query->prepare(queryString(queryName, version));
+ _queryCache[queryId] = query;
+ }
+
+ return _queryCache[queryId];
+}
+
+QSqlQuery *AbstractSqlStorage::cachedQuery(const QString &queryName) {
+ return cachedQuery(queryName, 0);
+}
+
+QStringList AbstractSqlStorage::setupQueries() {
+ QStringList queries;
+ QDir dir = QDir(QString(":/SQL/%1/%2/").arg(engineName()).arg(schemaVersion()));
+ foreach(QFileInfo fileInfo, dir.entryInfoList(QStringList() << "setup*", QDir::NoFilter, QDir::Name)) {
+ queries << queryString(fileInfo.baseName());
+ }
+ return queries;
+}
+
+bool AbstractSqlStorage::setup(const QVariantMap &settings) {
+ Q_UNUSED(settings)
+ QSqlDatabase db = logDb();
+ if(!db.isOpen()) {
+ qWarning() << "Unable to setup Logging Backend!";
+ return false;
+ }
+
+ foreach(QString queryString, setupQueries()) {
+ QSqlQuery query = db.exec(queryString);
+ if(!watchQuery(&query)) {
+ qWarning() << "Unable to setup Logging Backend!";
+ return false;
+ }
+ }
+ return true;
+}
+
+QStringList AbstractSqlStorage::upgradeQueries(int version) {
+ QStringList queries;
+ QDir dir = QDir(QString(":/SQL/%1/%2/").arg(engineName()).arg(version));
+ foreach(QFileInfo fileInfo, dir.entryInfoList(QStringList() << "upgrade*", QDir::NoFilter, QDir::Name)) {
+ qDebug() << queryString(fileInfo.baseName());
+ queries << queryString(fileInfo.baseName());
+ }
+ return queries;
+}
+
+bool AbstractSqlStorage::upgradeDb() {
+ if(schemaVersion() <= installedSchemaVersion())
+ return true;
+
+ QSqlDatabase db = logDb();
+
+ for(int ver = installedSchemaVersion() + 1; ver <= schemaVersion(); ver++) {
+ foreach(QString queryString, upgradeQueries(ver)) {
+ QSqlQuery query = db.exec(queryString);
+ if(!watchQuery(&query)) {
+ qWarning() << "Unable to upgrade Logging Backend!";
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+int AbstractSqlStorage::schemaVersion() {
+ // returns the newest Schema Version!
+ // not the currently used one! (though it can be the same)
+ if(_schemaVersion > 0)
+ return _schemaVersion;
+
+ int version;
+ bool ok;
+ QDir dir = QDir(":/SQL/" + engineName());
+ foreach(QFileInfo fileInfo, dir.entryInfoList()) {
+ if(!fileInfo.isDir())
+ continue;
+
+ version = fileInfo.fileName().toInt(&ok);
+ if(!ok)
+ continue;
+
+ if(version > _schemaVersion)
+ _schemaVersion = version;
+ }
+ return _schemaVersion;
+}
+
+bool AbstractSqlStorage::watchQuery(QSqlQuery *query) {
+ if(query->lastError().isValid()) {
+ qWarning() << "unhandled Error in QSqlQuery!";
+ qWarning() << " last Query:" << query->lastQuery();
+ qWarning() << " executed Query:" << query->executedQuery();
+ qWarning() << " bound Values:" << query->boundValues();
+ qWarning() << " Error Number:" << query->lastError().number();
+ qWarning() << " Error Message:" << query->lastError().text();
+ qWarning() << " Driver Message:" << query->lastError().driverText();
+ qWarning() << " DB Message:" << query->lastError().databaseText();
+
+ return false;
+ }
+ return true;
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2005-07 by the Quassel IRC Team *
+ * devel@quassel-irc.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) version 3. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef ABSTRACTSQLSTORAGE_H
+#define ABSTRACTSQLSTORAGE_H
+
+#include "storage.h"
+
+#include <QSqlDatabase>
+
+class QSqlQuery;
+
+class AbstractSqlStorage : public Storage {
+ Q_OBJECT
+
+public:
+ AbstractSqlStorage(QObject *parent = 0);
+ virtual ~AbstractSqlStorage();
+
+ //! Returns the name of the storage backend engine
+ /** \return A virtual equivalent of displayName() */
+ virtual QString engineName() { return ""; }
+
+protected:
+ bool init(const QVariantMap &settings = QVariantMap());
+
+ QSqlDatabase logDb();
+
+ QString queryString(const QString &queryName, int version);
+ QString queryString(const QString &queryName);
+
+ QSqlQuery *cachedQuery(const QString &queryName, int version);
+ QSqlQuery *cachedQuery(const QString &queryName);
+
+ QStringList setupQueries();
+ bool setup(const QVariantMap &settings = QVariantMap());
+
+ QStringList upgradeQueries(int ver);
+ bool upgradeDb();
+
+ bool watchQuery(QSqlQuery *query);
+
+ int schemaVersion();
+ virtual int installedSchemaVersion() { return -1; };
+
+ virtual QString driverName() = 0;
+ inline virtual QString hostName() { return QString(); }
+ virtual QString databaseName() = 0;
+ inline virtual QString userName() { return QString(); }
+ inline virtual QString password() { return QString(); }
+
+private:
+ bool openDb();
+
+ int _schemaVersion;
+
+ QHash<QPair<QString, int>, QSqlQuery *> _queryCache;
+
+};
+
+
+#endif
#include <QMetaObject>
#include <QMetaMethod>
+#include <QCoreApplication>
+
Core *Core::instanceptr = 0;
Core *Core::instance() {
instanceptr = 0;
}
-Core::Core() {
- storage = 0;
+Core::Core()
+ : storage(0)
+{
}
void Core::init() {
-
// TODO: Remove this again at some point
// Check if old core settings need to be migrated in order to make the switch to the
// new location less painful.
CoreSettings cs;
QVariant foo = cs.databaseSettings();
+
if(!foo.isValid()) {
// ok, no settings stored yet. check for old ones.
+#ifdef Q_WS_MAC
+ QSettings os("quassel-irc.org", "Quassel IRC", this);
+#else
QSettings os("Quassel IRC Development Team", "Quassel IRC");
+#endif
QVariant bar = os.value("Core/DatabaseSettings");
if(bar.isValid()) {
// old settings available -- migrate!
qWarning() << "\n\nOld settings detected. Will migrate core settings to the new location...\nNOTE: GUI style settings won't be migrated!\n";
+#ifdef Q_WS_MAC
+ QSettings ncs("quassel-irc.org", "Quassel Core");
+#else
QSettings ncs("Quassel Project", "Quassel Core");
+#endif
ncs.setValue("Core/CoreState", os.value("Core/CoreState"));
ncs.setValue("Core/DatabaseSettings", os.value("Core/DatabaseSettings"));
os.beginGroup("SessionData");
ncs.setValue(QString("CoreUser/%1/SessionData/Networks").arg(group), os.value(QString("%1/Networks").arg(group)));
}
os.endGroup();
-
+#ifdef Q_WS_MAC
+ QSettings ngs("quassel-irc.org", "Quassel Client");
+#else
QSettings ngs("Quassel Project", "Quassel Client");
+#endif
os.beginGroup("Accounts");
foreach(QString key, os.childKeys()) {
ngs.setValue(QString("Accounts/%1").arg(key), os.value(key));
}
// END
- CoreSettings s;
configured = false;
- QVariantMap dbSettings = s.databaseSettings().toMap();
- QString hname = dbSettings["Type"].toString().toLower();
- hname[0] = hname[0].toUpper();
- hname = "initStorage" + hname;
- if (!QMetaObject::invokeMethod(this, hname.toAscii(), Q_RETURN_ARG(bool, configured), Q_ARG(QVariantMap, dbSettings), Q_ARG(bool, false))) {
- qWarning("No database backend configured.");
- }
-
- if (!configured) {
+ if(!(configured = initStorage(cs.databaseSettings().toMap()))) {
qWarning("Core is currently not configured!");
}
-
+
connect(&server, SIGNAL(newConnection()), this, SLOT(incomingConnection()));
- startListening(s.port());
+ startListening(cs.port());
guiUser = 0;
}
-bool Core::initStorageSqlite(QVariantMap dbSettings, bool setup) {
- if (!SqliteStorage::isAvailable()) {
- qFatal("Sqlite is currently required! Please make sure your Qt library has sqlite support enabled.");
- }
- if (storage) {
+bool Core::initStorage(QVariantMap dbSettings, bool setup) {
+ QString engine = dbSettings["Type"].toString().toLower();
+
+ if(storage) {
qDebug() << "Deleting old storage object.";
- delete storage;
- storage = NULL;
+ storage->deleteLater();
+ storage = 0;
}
-
- storage = new SqliteStorage();
- if (setup && !storage->setup(dbSettings)) {
- return false;
+
+ // FIXME register new storageProviders here
+ if(engine == "sqlite" && SqliteStorage::isAvailable()) {
+ storage = new SqliteStorage(this);
+ } else {
+ qWarning() << "Selected StorageBackend is not available:" << dbSettings["Type"].toString();
+ return configured = false;
}
-
- return storage->init(dbSettings);
+
+ if(setup && !storage->setup(dbSettings)) {
+ return configured = false;
+ }
+
+ return configured = storage->init(dbSettings);
+}
+
+bool Core::initStorage(QVariantMap dbSettings) {
+ return initStorage(dbSettings, false);
}
Core::~Core() {
qDeleteAll(sessions);
- if (storage) {
- delete storage;
- storage = NULL;
- }
}
void Core::restoreState() {
return;
}
}
- blockSizes[socket] = bsize = 0; // FIXME blockSizes aufr�um0rn!
+ blockSizes[socket] = bsize = 0; // FIXME blockSizes aufräum0rn!
}
// FIXME: no longer called, since connection handling is now in SignalProxy
msg.remove("User");
msg.remove("Password");
qDebug() << "Initializing storage provider" << msg["Type"].toString();
- QString hname = msg["Type"].toString().toLower();
- hname[0] = hname[0].toUpper();
- hname = "initStorage" + hname;
- if (!QMetaObject::invokeMethod(this, hname.toAscii(), Q_RETURN_ARG(bool, configured), Q_ARG(QVariantMap, msg), Q_ARG(bool, true))) {
- qWarning("No database backend configured.");
- }
- if (!configured) {
+
+ if(!initStorage(msg, true)) {
// notify client to start wizard again
qWarning("Core is currently not configured!");
QVariantMap reply;
storageProviders.append(SqliteStorage::displayName());
}
// TODO: temporary
- storageProviders.append("MySQL");
+ // storageProviders.append("MySQL");
return storageProviders;
}
void clientHasData();
void clientDisconnected();
- bool initStorageSqlite(QVariantMap dbSettings, bool setup);
+ bool initStorage(QVariantMap dbSettings, bool setup);
+ bool initStorage(QVariantMap dbSettings);
private:
Core();
DEPMOD = common
QT_MOD = core network sql script
-SRCS = core.cpp coresession.cpp coresettings.cpp server.cpp sqlitestorage.cpp storage.cpp basichandler.cpp \
+SRCS = core.cpp coresession.cpp coresettings.cpp server.cpp sqlitestorage.cpp abstractsqlstorage.cpp storage.cpp basichandler.cpp \
ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp coreusersettings.cpp
-HDRS = core.h coresession.h coresettings.h server.h sqlitestorage.h storage.h basichandler.h \
+HDRS = core.h coresession.h coresettings.h server.h sqlitestorage.h abstractsqlstorage.h storage.h basichandler.h \
ircserverhandler.h userinputhandler.h ctcphandler.h coreusersettings.h
--- /dev/null
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>./SQL/SQLite/1/delete_backlog_by_uid.sql</file>
+ <file>./SQL/SQLite/1/delete_buffers_by_uid.sql</file>
+ <file>./SQL/SQLite/1/delete_networks_by_uid.sql</file>
+ <file>./SQL/SQLite/1/delete_quasseluser.sql</file>
+ <file>./SQL/SQLite/1/insert_buffer.sql</file>
+ <file>./SQL/SQLite/1/insert_message.sql</file>
+ <file>./SQL/SQLite/1/insert_network.sql</file>
+ <file>./SQL/SQLite/1/insert_quasseluser.sql</file>
+ <file>./SQL/SQLite/1/insert_sender.sql</file>
+ <file>./SQL/SQLite/1/select_authuser.sql</file>
+ <file>./SQL/SQLite/1/select_bufferByName.sql</file>
+ <file>./SQL/SQLite/1/select_buffers.sql</file>
+ <file>./SQL/SQLite/1/select_lastMessage.sql</file>
+ <file>./SQL/SQLite/1/select_messageRange.sql</file>
+ <file>./SQL/SQLite/1/select_messages.sql</file>
+ <file>./SQL/SQLite/1/select_messagesOffset.sql</file>
+ <file>./SQL/SQLite/1/select_messagesSince.sql</file>
+ <file>./SQL/SQLite/1/select_messagesSinceOffset.sql</file>
+ <file>./SQL/SQLite/1/select_userid.sql</file>
+ <file>./SQL/SQLite/1/setup_000_quasseluser.sql</file>
+ <file>./SQL/SQLite/1/setup_010_sender.sql</file>
+ <file>./SQL/SQLite/1/setup_020_network.sql</file>
+ <file>./SQL/SQLite/1/setup_040_buffer.sql</file>
+ <file>./SQL/SQLite/1/setup_050_buffer_idx.sql</file>
+ <file>./SQL/SQLite/1/setup_060_backlog.sql</file>
+ <file>./SQL/SQLite/1/setup_070_coreinfo.sql</file>
+ <file>./SQL/SQLite/1/setup_080_version.sql</file>
+ <file>./SQL/SQLite/1/update_username.sql</file>
+ <file>./SQL/SQLite/1/update_userpassword.sql</file>
+ <file>./SQL/SQLite/1/upgrade_000_drop_coreinfo.sql</file>
+ <file>./SQL/SQLite/1/upgrade_010_create_coreinfo.sql</file>
+ <file>./SQL/SQLite/1/upgrade_020_update_schemaversion.sql</file>
+</qresource>
+</RCC>
/***************************************************************************
- * Copyright (C) 2005-08 by the Quassel Project *
+ * Copyright (C) 2005-07 by the Quassel IRC Team *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#include "sqlitestorage.h"
+#include <QCryptographicHash>
+
#include <QtSql>
-SqliteStorage::SqliteStorage() {
- logMessageQuery = NULL;
- addSenderQuery = NULL;
- getLastMessageIdQuery = NULL;
- requestMsgsQuery = NULL;
- requestMsgsOffsetQuery = NULL;
- requestMsgsSinceQuery = NULL;
- requestMsgsSinceOffsetQuery = NULL;
- requestMsgRangeQuery = NULL;
- createNetworkQuery = NULL;
- createBufferQuery = NULL;
- getBufferInfoQuery = NULL;
+SqliteStorage::SqliteStorage(QObject *parent)
+ : AbstractSqlStorage(parent)
+{
}
SqliteStorage::~SqliteStorage() {
- if (logMessageQuery) delete logMessageQuery;
- if (addSenderQuery) delete addSenderQuery;
- if (getLastMessageIdQuery) delete getLastMessageIdQuery;
- if (requestMsgsQuery) delete requestMsgsQuery;
- if (requestMsgsOffsetQuery) delete requestMsgsOffsetQuery;
- if (requestMsgsSinceQuery) delete requestMsgsSinceQuery;
- if (requestMsgsSinceOffsetQuery) delete requestMsgsSinceOffsetQuery;
- if (requestMsgRangeQuery) delete requestMsgRangeQuery;
- if (createNetworkQuery) delete createNetworkQuery;
- if (createBufferQuery) delete createBufferQuery;
- if (getBufferInfoQuery) delete getBufferInfoQuery;
-
- logDb.close();
}
bool SqliteStorage::isAvailable() {
}
QString SqliteStorage::displayName() {
- return QString("SQlite");
+ return QString("SQLite");
}
-bool SqliteStorage::setup(const QVariantMap &settings) {
- Q_UNUSED(settings);
- bool ok;
- // this extra scope is needed to be able to remove the database connection later
- {
- logDb = QSqlDatabase::addDatabase("QSQLITE", "quassel_setup");
- logDb.setDatabaseName(SqliteStorage::backlogFile(true));
- ok = logDb.open();
-
- if (!ok) {
- qWarning(tr("Could not open backlog database: %1").arg(logDb.lastError().text()).toAscii());
- } else {
- logDb.exec("CREATE TABLE quasseluser ("
- "userid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
- "username TEXT UNIQUE NOT NULL,"
- "password BLOB NOT NULL)");
-
- logDb.exec("CREATE TABLE sender ("
- "senderid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
- "sender TEXT UNIQUE NOT NULL)");
-
- logDb.exec("CREATE TABLE network ("
- "networkid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
- "userid INTEGER NOT NULL,"
- "networkname TEXT NOT NULL,"
- "UNIQUE (userid, networkname))");
-
- logDb.exec("CREATE TABLE buffergroup ("
- "groupid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
- "userid INTEGER NOT NULL,"
- "displayname TEXT)");
-
- logDb.exec("CREATE TABLE buffer ("
- "bufferid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
- "userid INTEGER NOT NULL,"
- "groupid INTEGER,"
- "networkid INTEGER NOT NULL,"
- "buffername TEXT NOT NULL)");
-
- logDb.exec("CREATE UNIQUE INDEX buffer_idx "
- "ON buffer(userid, networkid, buffername)");
-
- logDb.exec("CREATE TABLE backlog ("
- "messageid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
- "time INTEGER NOT NULL,"
- "bufferid INTEGER NOT NULL,"
- "type INTEGER NOT NULL,"
- "flags INTEGER NOT NULL,"
- "senderid INTEGER NOT NULL,"
- "message TEXT)");
-
- logDb.exec("CREATE TABLE coreinfo ("
- "updateid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,"
- "version INTEGER NOT NULL)");
-
- logDb.exec("INSERT INTO coreinfo (version) VALUES (0)");
-
- // something fucked up -> no logging possible
- // FIXME logDb.lastError is reset whenever exec is called
- if(logDb.lastError().isValid()) {
- qWarning(tr("Could not create backlog table: %1").arg(logDb.lastError().text()).toAscii());
- qWarning(tr("Disabling logging...").toAscii());
- Q_ASSERT(false); // quassel does require logging
- ok = false;
- }
-
- logDb.close();
- }
- }
-
- QSqlDatabase::removeDatabase("quassel_setup");
- return ok;
+QString SqliteStorage::engineName() {
+ return SqliteStorage::displayName();
}
-bool SqliteStorage::init(const QVariantMap &settings) {
- Q_UNUSED(settings);
- bool ok;
- // i need the extra scope to be able to remove the database connection
- {
- logDb = QSqlDatabase::database("quassel_connection", false);
- if (!logDb.isValid()) {
- logDb = QSqlDatabase::addDatabase("QSQLITE", "quassel_connection");
- }
- logDb.setDatabaseName(SqliteStorage::backlogFile());
- ok = logDb.open();
- if (!ok) {
- qWarning(tr("Could not open backlog database: %1").arg(logDb.lastError().text()).toAscii());
- }
- }
-
- if (!ok) {
- //QSqlDatabase::removeDatabase("quassel_connection");
- return false;
- }
+int SqliteStorage::installedSchemaVersion() {
+ QSqlQuery query = logDb().exec("SELECT value FROM coreinfo WHERE key = 'schemaversion'");
+ if(query.first())
+ return query.value(0).toInt();
- // check if the db schema is up to date
- QSqlQuery query = logDb.exec("SELECT MAX(version) FROM coreinfo");
- if(query.first()) {
- // TODO VersionCheck
- //checkVersion(query.value(0));
- qDebug() << "Sqlite is ready. Quassel Schema Version:" << query.value(0).toUInt();
- } else {
- qWarning("Sqlite is not ready!");
- return false;
- }
+ // maybe it's really old... (schema version 0)
+ query = logDb().exec("SELECT MAX(version) FROM coreinfo");
+ if(query.first())
+ return query.value(0).toInt();
- // we will need those pretty often... so let's speed things up:
- createBufferQuery = new QSqlQuery(logDb);
- createBufferQuery->prepare("INSERT INTO buffer (userid, networkid, buffername) VALUES (:userid, (SELECT networkid FROM network WHERE networkname = :networkname AND userid = :userid2), :buffername)");
-
- createNetworkQuery = new QSqlQuery(logDb);
- createNetworkQuery->prepare("INSERT INTO network (userid, networkname) VALUES (:userid, :networkname)");
-
- getBufferInfoQuery = new QSqlQuery(logDb);
- getBufferInfoQuery->prepare("SELECT bufferid FROM buffer "
- "JOIN network ON buffer.networkid = network.networkid "
- "WHERE network.networkname = :networkname AND network.userid = :userid AND buffer.userid = :userid2 AND lower(buffer.buffername) = lower(:buffername)");
-
- logMessageQuery = new QSqlQuery(logDb);
- logMessageQuery->prepare("INSERT INTO backlog (time, bufferid, type, flags, senderid, message) "
- "VALUES (:time, :bufferid, :type, :flags, (SELECT senderid FROM sender WHERE sender = :sender), :message)");
-
- addSenderQuery = new QSqlQuery(logDb);
- addSenderQuery->prepare("INSERT INTO sender (sender) VALUES (:sender)");
-
- getLastMessageIdQuery = new QSqlQuery(logDb);
- getLastMessageIdQuery->prepare("SELECT messageid FROM backlog "
- "WHERE time = :time AND bufferid = :bufferid AND type = :type AND senderid = (SELECT senderid FROM sender WHERE sender = :sender)");
-
- requestMsgsOffsetQuery = new QSqlQuery(logDb);
- requestMsgsOffsetQuery->prepare("SELECT count(*) FROM backlog WHERE bufferid = :bufferid AND messageid < :messageid");
-
- requestMsgsQuery = new QSqlQuery(logDb);
- requestMsgsQuery->prepare("SELECT messageid, time, type, flags, sender, message, displayname "
- "FROM backlog "
- "JOIN buffer ON backlog.bufferid = buffer.bufferid "
- "JOIN sender ON backlog.senderid = sender.senderid "
- "LEFT JOIN buffergroup ON buffer.groupid = buffergroup.groupid "
- "WHERE buffer.bufferid = :bufferid OR buffer.groupid = (SELECT groupid FROM buffer WHERE bufferid = :bufferid2) "
- "ORDER BY messageid DESC "
- "LIMIT :limit OFFSET :offset");
-
- requestMsgsSinceOffsetQuery = new QSqlQuery(logDb);
- requestMsgsSinceOffsetQuery->prepare("SELECT count(*) FROM backlog WHERE bufferid = :bufferid AND time >= :since");
-
- requestMsgsSinceQuery = new QSqlQuery(logDb);
- requestMsgsSinceQuery->prepare("SELECT messageid, time, type, flags, sender, message, displayname "
- "FROM backlog "
- "JOIN buffer ON backlog.bufferid = buffer.bufferid "
- "JOIN sender ON backlog.senderid = sender.senderid "
- "LEFT JOIN buffergroup ON buffer.groupid = buffergroup.groupid "
- "WHERE (buffer.bufferid = :bufferid OR buffer.groupid = (SELECT groupid FROM buffer WHERE bufferid = :bufferid2)) AND "
- "backlog.time >= :since "
- "ORDER BY messageid DESC "
- "LIMIT -1 OFFSET :offset");
-
- requestMsgRangeQuery = new QSqlQuery(logDb);
- requestMsgRangeQuery->prepare("SELECT messageid, time, type, flags, sender, message, displayname "
- "FROM backlog "
- "JOIN buffer ON backlog.bufferid = buffer.bufferid "
- "JOIN sender ON backlog.senderid = sender.senderid "
- "LEFT JOIN buffergroup ON buffer.groupid = buffergroup.groupid "
- "WHERE (buffer.bufferid = :bufferid OR buffer.groupid = (SELECT groupid FROM buffer WHERE bufferid = :bufferid2)) AND "
- "backlog.messageid >= :firstmsg AND backlog.messageid <= :lastmsg "
- "ORDER BY messageid DESC ");
-
- return true;
+ return AbstractSqlStorage::installedSchemaVersion();
}
UserId SqliteStorage::addUser(const QString &user, const QString &password) {
QByteArray cryptopass = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha1);
cryptopass = cryptopass.toHex();
- QSqlQuery query(logDb);
- query.prepare("INSERT INTO quasseluser (username, password) VALUES (:username, :password)");
+ QSqlQuery query(logDb());
+ query.prepare(queryString("insert_quasseluser"));
query.bindValue(":username", user);
query.bindValue(":password", cryptopass);
query.exec();
return 0;
}
- query.prepare("SELECT userid FROM quasseluser WHERE username = :username");
+ query.prepare(queryString("select_userid"));
query.bindValue(":username", user);
query.exec();
query.first();
QByteArray cryptopass = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha1);
cryptopass = cryptopass.toHex();
- QSqlQuery query(logDb);
- query.prepare("UPDATE quasseluser SET password = :password WHERE userid = :userid");
+ QSqlQuery query(logDb());
+ query.prepare(queryString("update_userpassword"));
query.bindValue(":userid", user);
query.bindValue(":password", cryptopass);
query.exec();
}
void SqliteStorage::renameUser(UserId user, const QString &newName) {
- QSqlQuery query(logDb);
- query.prepare("UPDATE quasseluser SET username = :username WHERE userid = :userid");
+ QSqlQuery query(logDb());
+ query.prepare(queryString("update_username"));
query.bindValue(":userid", user);
query.bindValue(":username", newName);
query.exec();
QByteArray cryptopass = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha1);
cryptopass = cryptopass.toHex();
- QSqlQuery query(logDb);
- query.prepare("SELECT userid FROM quasseluser WHERE username = :username AND password = :password");
+ QSqlQuery query(logDb());
+ query.prepare(queryString("select_authuser"));
query.bindValue(":username", user);
query.bindValue(":password", cryptopass);
query.exec();
return query.value(0).toUInt();
} else {
throw AuthError();
- //return 0;
+ return 0;
}
}
void SqliteStorage::delUser(UserId user) {
- QSqlQuery query(logDb);
- query.prepare("DELETE FROM backlog WHERE bufferid IN (SELECT DISTINCT bufferid FROM buffer WHERE userid = :userid");
+ QSqlQuery query(logDb());
+ query.prepare(queryString("delete_backlog_by_uid"));
query.bindValue(":userid", user);
query.exec();
- query.prepare("DELETE FROM buffer WHERE userid = :userid");
- query.bindValue(":userid", user);
- query.exec();
- query.prepare("DELETE FROM buffergroup WHERE userid = :userid");
+
+ query.prepare(queryString("delete_buffers_by_uid"));
query.bindValue(":userid", user);
query.exec();
- query.prepare("DELETE FROM network WHERE userid = :userid");
+
+ query.prepare(queryString("delete_networks_by_uid"));
query.bindValue(":userid", user);
query.exec();
- query.prepare("DELETE FROM quasseluser WHERE userid = :userid");
+
+ query.prepare(queryString("delete_quasseluser"));
query.bindValue(":userid", user);
query.exec();
// I hate the lack of foreign keys and on delete cascade... :(
}
void SqliteStorage::createBuffer(UserId user, const QString &network, const QString &buffer) {
+ QSqlQuery *createBufferQuery = cachedQuery("insert_buffer");
createBufferQuery->bindValue(":userid", user);
createBufferQuery->bindValue(":userid2", user); // Qt can't handle same placeholder twice (maybe sqlites fault)
createBufferQuery->bindValue(":networkname", network);
createBufferQuery->exec();
if(createBufferQuery->lastError().isValid()) {
- if(createBufferQuery->lastError().number() == 19) { // Null Constraint violation
+ if(createBufferQuery->lastError().number() == 19) { // Null Constraint violation
+ QSqlQuery *createNetworkQuery = cachedQuery("insert_network");
createNetworkQuery->bindValue(":userid", user);
createNetworkQuery->bindValue(":networkname", network);
createNetworkQuery->exec();
}
uint SqliteStorage::getNetworkId(UserId user, const QString &network) {
- QSqlQuery query(logDb);
+ QSqlQuery query(logDb());
query.prepare("SELECT networkid FROM network "
"WHERE userid = :userid AND networkname = :networkname");
query.bindValue(":userid", user);
BufferInfo bufferid;
// TODO: get rid of this hackaround
uint networkId = getNetworkId(user, network);
+
+ QSqlQuery *getBufferInfoQuery = cachedQuery("select_bufferByName");
getBufferInfoQuery->bindValue(":networkname", network);
getBufferInfoQuery->bindValue(":userid", user);
getBufferInfoQuery->bindValue(":userid2", user); // Qt can't handle same placeholder twice... though I guess it's sqlites fault
}
QList<BufferInfo> SqliteStorage::requestBuffers(UserId user, QDateTime since) {
+ uint time = 0;
+ if(since.isValid())
+ time = since.toTime_t();
+
QList<BufferInfo> bufferlist;
- QSqlQuery query(logDb);
- query.prepare("SELECT DISTINCT buffer.bufferid, networkname, buffername FROM buffer "
- "JOIN network ON buffer.networkid = network.networkid "
- "JOIN backlog ON buffer.bufferid = backlog.bufferid "
- "WHERE buffer.userid = :userid AND time >= :time");
+ QSqlQuery query(logDb());
+ query.prepare(queryString("select_buffers"));
query.bindValue(":userid", user);
- if (since.isValid()) {
- query.bindValue(":time", since.toTime_t());
- } else {
- query.bindValue(":time", 0);
- }
+ query.bindValue(":time", time);
query.exec();
-
+ watchQuery(&query);
while(query.next()) {
- bufferlist << BufferInfo(query.value(0).toUInt(), getNetworkId(user, query.value(1).toString()), 0, query.value(1).toString(), query.value(2).toString());
+ bufferlist << BufferInfo(query.value(0).toUInt(), query.value(2).toUInt(), 0, query.value(3).toString(), query.value(1).toString());
}
return bufferlist;
}
MsgId SqliteStorage::logMessage(Message msg) {
+ QSqlQuery *logMessageQuery = cachedQuery("insert_message");
logMessageQuery->bindValue(":time", msg.timestamp().toTime_t());
logMessageQuery->bindValue(":bufferid", msg.buffer().uid());
logMessageQuery->bindValue(":type", msg.type());
if(logMessageQuery->lastError().isValid()) {
// constraint violation - must be NOT NULL constraint - probably the sender is missing...
- if(logMessageQuery->lastError().number() == 19) {
+ if(logMessageQuery->lastError().number() == 19) {
+ QSqlQuery *addSenderQuery = cachedQuery("insert_sender");
addSenderQuery->bindValue(":sender", msg.sender());
addSenderQuery->exec();
watchQuery(addSenderQuery);
}
}
+ QSqlQuery *getLastMessageIdQuery = cachedQuery("select_lastMessage");
getLastMessageIdQuery->bindValue(":time", msg.timestamp().toTime_t());
getLastMessageIdQuery->bindValue(":bufferid", msg.buffer().uid());
getLastMessageIdQuery->bindValue(":type", msg.type());
QList<Message> SqliteStorage::requestMsgs(BufferInfo buffer, int lastmsgs, int offset) {
QList<Message> messagelist;
// we have to determine the real offset first
+ QSqlQuery *requestMsgsOffsetQuery = cachedQuery("select_messagesOffset");
requestMsgsOffsetQuery->bindValue(":bufferid", buffer.uid());
requestMsgsOffsetQuery->bindValue(":messageid", offset);
requestMsgsOffsetQuery->exec();
offset = requestMsgsOffsetQuery->value(0).toUInt();
// now let's select the messages
+ QSqlQuery *requestMsgsQuery = cachedQuery("select_messages");
requestMsgsQuery->bindValue(":bufferid", buffer.uid());
requestMsgsQuery->bindValue(":bufferid2", buffer.uid()); // Qt can't handle the same placeholder used twice
requestMsgsQuery->bindValue(":limit", lastmsgs);
QList<Message> SqliteStorage::requestMsgs(BufferInfo buffer, QDateTime since, int offset) {
QList<Message> messagelist;
// we have to determine the real offset first
+ QSqlQuery *requestMsgsSinceOffsetQuery = cachedQuery("select_messagesSinceOffset");
requestMsgsSinceOffsetQuery->bindValue(":bufferid", buffer.uid());
requestMsgsSinceOffsetQuery->bindValue(":since", since.toTime_t());
requestMsgsSinceOffsetQuery->exec();
offset = requestMsgsSinceOffsetQuery->value(0).toUInt();
// now let's select the messages
+ QSqlQuery *requestMsgsSinceQuery = cachedQuery("select_messagesSince");
requestMsgsSinceQuery->bindValue(":bufferid", buffer.uid());
requestMsgsSinceQuery->bindValue(":bufferid2", buffer.uid());
requestMsgsSinceQuery->bindValue(":since", since.toTime_t());
QList<Message> SqliteStorage::requestMsgRange(BufferInfo buffer, int first, int last) {
QList<Message> messagelist;
+ QSqlQuery *requestMsgRangeQuery = cachedQuery("select_messageRange");
requestMsgRangeQuery->bindValue(":bufferid", buffer.uid());
requestMsgRangeQuery->bindValue(":bufferid2", buffer.uid());
requestMsgRangeQuery->bindValue(":firstmsg", first);
return messagelist;
}
-QString SqliteStorage::backlogFile(bool createPath) {
+QString SqliteStorage::backlogFile() {
// kinda ugly, but I currently see no other way to do that
#ifdef Q_OS_WIN32
QString quasselDir = QDir::homePath() + qgetenv("APPDATA") + "\\quassel\\";
#else
QString quasselDir = QDir::homePath() + "/.quassel/";
#endif
-
- if (createPath) {
- QDir *qDir = new QDir(quasselDir);
- if (!qDir->exists(quasselDir)) {
- qDir->mkpath(quasselDir);
- }
- delete qDir;
- }
- return quasselDir + "quassel-storage.sqlite";
+ QDir qDir(quasselDir);
+ if(!qDir.exists(quasselDir))
+ qDir.mkpath(quasselDir);
+
+ return quasselDir + "quassel-storage.sqlite";
}
-bool SqliteStorage::watchQuery(QSqlQuery *query) {
- if(query->lastError().isValid()) {
- qWarning() << "unhandled Error in QSqlQuery!";
- qWarning() << " last Query:" << query->lastQuery();
- qWarning() << " executed Query:" << query->executedQuery();
- qWarning() << " bound Values:" << query->boundValues();
- qWarning() << " Error Number:" << query->lastError().number();
- qWarning() << " Error Message:" << query->lastError().text();
- qWarning() << " Driver Message:" << query->lastError().driverText();
- qWarning() << " DB Message:" << query->lastError().databaseText();
-
- return false;
- }
- return true;
-}
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
-#ifndef _SQLITESTORAGE_H_
-#define _SQLITESTORAGE_H_
+#ifndef SQLITESTORAGE_H
+#define SQLITESTORAGE_H
-#include <QCryptographicHash>
+#include "abstractsqlstorage.h"
-#include "storage.h"
+#include <QSqlDatabase>
class QSqlQuery;
-class SqliteStorage : public Storage {
+class SqliteStorage : public AbstractSqlStorage {
Q_OBJECT
- public:
- SqliteStorage();
- virtual ~SqliteStorage();
-
- public slots:
- /* General */
-
- static bool isAvailable();
- static QString displayName();
- virtual bool setup(const QVariantMap &settings = QVariantMap());
- virtual bool init(const QVariantMap &settings = QVariantMap());
-
- // TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc
-
- /* User handling */
-
- virtual UserId addUser(const QString &user, const QString &password);
- virtual void updateUser(UserId user, const QString &password);
- virtual void renameUser(UserId user, const QString &newName);
- virtual UserId validateUser(const QString &user, const QString &password);
- virtual void delUser(UserId user);
-
- /* Network handling */
- virtual uint getNetworkId(UserId user, const QString &network);
-
- /* Buffer handling */
- virtual BufferInfo getBufferInfo(UserId user, const QString &network, const QString &buffer = "");
- virtual QList<BufferInfo> requestBuffers(UserId user, QDateTime since = QDateTime());
-
- /* Message handling */
-
- virtual MsgId logMessage(Message msg);
- virtual QList<Message> requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1);
- virtual QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1);
- virtual QList<Message> requestMsgRange(BufferInfo buffer, int first, int last);
-
- signals:
- void bufferInfoUpdated(BufferInfo);
-
- protected:
-
- private:
- static QString backlogFile(bool createPath = false);
-
- void createBuffer(UserId user, const QString &network, const QString &buffer);
- bool watchQuery(QSqlQuery *query);
-
- QSqlDatabase logDb;
-
- QSqlQuery *logMessageQuery;
- QSqlQuery *addSenderQuery;
- QSqlQuery *getLastMessageIdQuery;
- QSqlQuery *requestMsgsQuery;
- QSqlQuery *requestMsgsOffsetQuery;
- QSqlQuery *requestMsgsSinceQuery;
- QSqlQuery *requestMsgsSinceOffsetQuery;
- QSqlQuery *requestMsgRangeQuery;
- QSqlQuery *createNetworkQuery;
- QSqlQuery *createBufferQuery;
- QSqlQuery *getBufferInfoQuery;
+public:
+ SqliteStorage(QObject *parent = 0);
+ virtual ~SqliteStorage();
+
+public slots:
+ /* General */
+
+ static bool isAvailable();
+ static QString displayName();
+ virtual QString engineName() ;
+ // TODO: Add functions for configuring the backlog handling, i.e. defining auto-cleanup settings etc
+
+ /* User handling */
+
+ virtual UserId addUser(const QString &user, const QString &password);
+ virtual void updateUser(UserId user, const QString &password);
+ virtual void renameUser(UserId user, const QString &newName);
+ virtual UserId validateUser(const QString &user, const QString &password);
+ virtual void delUser(UserId user);
+
+ /* Network handling */
+ virtual uint getNetworkId(UserId user, const QString &network);
+
+ /* Buffer handling */
+ virtual BufferInfo getBufferInfo(UserId user, const QString &network, const QString &buffer = "");
+ virtual QList<BufferInfo> requestBuffers(UserId user, QDateTime since = QDateTime());
+
+ /* Message handling */
+
+ virtual MsgId logMessage(Message msg);
+ virtual QList<Message> requestMsgs(BufferInfo buffer, int lastmsgs = -1, int offset = -1);
+ virtual QList<Message> requestMsgs(BufferInfo buffer, QDateTime since, int offset = -1);
+ virtual QList<Message> requestMsgRange(BufferInfo buffer, int first, int last);
+
+protected:
+ inline virtual QString driverName() { return "QSQLITE"; }
+ inline virtual QString databaseName() { return backlogFile(); }
+ virtual int installedSchemaVersion();
+
+signals:
+ void bufferInfoUpdated(BufferInfo);
+
+private:
+ static QString backlogFile();
+ void createBuffer(UserId user, const QString &network, const QString &buffer);
};
#endif
***************************************************************************/
#include "storage.h"
+
+Storage::Storage(QObject *parent)
+ : QObject(parent)
+{
+}
#define _STORAGE_H_
#include <QtCore>
-#include <QSqlDatabase>
#include "message.h"
Q_OBJECT
public:
- Storage() {};
+ Storage(QObject *parent = 0);
virtual ~Storage() {};
public slots: