print sql queries when running core in debug mode
[quassel.git] / src / core / abstractsqlstorage.h
index 6fefb78..d0046a9 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-07 by the Quassel IRC Team                         *
+ *   Copyright (C) 2005-07 by the Quassel Project                          *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #include "storage.h"
 
 #include <QSqlDatabase>
+#include <QSqlQuery>
+#include <QSqlError>
 
-class QSqlQuery;
+class AbstractSqlMigrationReader;
+class AbstractSqlMigrationWriter;
 
 class AbstractSqlStorage : public Storage {
   Q_OBJECT
@@ -34,47 +37,291 @@ 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 ""; }
-  
+  virtual inline AbstractSqlMigrationReader *createMigrationReader() { return 0; }
+  virtual inline AbstractSqlMigrationWriter *createMigrationWriter() { return 0; }
+
+public slots:
+  virtual State init(const QVariantMap &settings = QVariantMap());
+  virtual bool setup(const QVariantMap &settings = QVariantMap());
+
 protected:
-  bool init(const QVariantMap &settings = QVariantMap());
-  virtual void sync();
-  
+  inline virtual void sync() {};
+
   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);
+  QString queryString(const QString &queryName, int version);
+  inline QString queryString(const QString &queryName) { return queryString(queryName, 0); }
 
   QStringList setupQueries();
-  bool setup(const QVariantMap &settings = QVariantMap());
 
   QStringList upgradeQueries(int ver);
   bool upgradeDb();
 
-  bool watchQuery(QSqlQuery *query);
-  
+  bool watchQuery(QSqlQuery &query);
+
   int schemaVersion();
   virtual int installedSchemaVersion() { return -1; };
+  virtual bool updateSchemaVersion(int newVersion) = 0;
+  virtual bool setupSchemaVersion(int version) = 0;
 
+  virtual void setConnectionProperties(const QVariantMap &properties) = 0;
   virtual QString driverName() = 0;
   inline virtual QString hostName() { return QString(); }
+  inline virtual int port() { return -1; }
   virtual QString databaseName() = 0;
   inline virtual QString userName() { return QString(); }
   inline virtual QString password() { return QString(); }
 
+
+  //! Initialize db specific features on connect
+  /** This is called every time a connection to a specific SQL backend is established
+   *  the default implementation does nothing.
+   *
+   *  When reimplementing this method, don't use logDB() inside this function as
+   *  this would cause as we're just about to initialize that DB connection.
+   */
+  inline virtual void initDbSession(QSqlDatabase & /* db */) {}
+
+private slots:
+  void connectionDestroyed();
+
 private:
-  bool openDb();
+  void addConnectionToPool();
 
   int _schemaVersion;
+  bool _debug;
+
+  static int _nextConnectionId;
+  QMutex _connectionPoolMutex;
+  // we let a Connection Object manage each actual db connection
+  // those objects reside in the thread the connection belongs to
+  // which allows us thread safe termination of a connection
+  class Connection;
+  QHash<QThread *, Connection *> _connectionPool;
+};
+
+// ========================================
+//  AbstractSqlStorage::Connection
+// ========================================
+class AbstractSqlStorage::Connection : public QObject {
+  Q_OBJECT
+
+public:
+  Connection(const QString &name, QObject *parent = 0);
+  ~Connection();
+
+  inline QLatin1String name() const { return QLatin1String(_name); }
+
+private:
+  QByteArray _name;
+};
+
+
+// ========================================
+//  AbstractSqlMigrator
+// ========================================
+class AbstractSqlMigrator {
+public:
+  // migration objects
+  struct QuasselUserMO {
+    UserId id;
+    QString username;
+    QString password;
+  };
+
+  struct SenderMO {
+    int senderId;
+    QString sender;
+    SenderMO() : senderId(0) {}
+  };
+
+  struct IdentityMO {
+    IdentityId id;
+    UserId userid;
+    QString identityname;
+    QString realname;
+    QString awayNick;
+    bool awayNickEnabled;
+    QString awayReason;
+    bool awayReasonEnabled;
+    bool autoAwayEnabled;
+    int autoAwayTime;
+    QString autoAwayReason;
+    bool autoAwayReasonEnabled;
+    bool detachAwayEnabled;
+    QString detachAwayReason;
+    bool detchAwayReasonEnabled;
+    QString ident;
+    QString kickReason;
+    QString partReason;
+    QString quitReason;
+    QByteArray sslCert;
+    QByteArray sslKey;
+  };
+
+  struct IdentityNickMO {
+    int nickid;
+    IdentityId identityId;
+    QString nick;
+  };
 
-  QHash<QPair<QString, int>, QSqlQuery *> _queryCache;
+  struct NetworkMO {
+    NetworkId networkid;
+    UserId userid;
+    QString networkname;
+    IdentityId identityid;
+    QString encodingcodec;
+    QString decodingcodec;
+    QString servercodec;
+    bool userandomserver;
+    QString perform;
+    bool useautoidentify;
+    QString autoidentifyservice;
+    QString autoidentifypassword;
+    bool useautoreconnect;
+    int autoreconnectinterval;
+    int autoreconnectretries;
+    bool unlimitedconnectretries;
+    bool rejoinchannels;
+    bool connected;
+    QString usermode;
+    QString awaymessage;
+    QString attachperform;
+    QString detachperform;
+    bool usesasl;
+    QString saslaccount;
+    QString saslpassword;
+  };
 
+  struct BufferMO {
+    BufferId bufferid;
+    UserId userid;
+    int groupid;
+    NetworkId networkid;
+    QString buffername;
+    QString buffercname;
+    int buffertype;
+    int lastseenmsgid;
+    int markerlinemsgid;
+    QString key;
+    bool joined;
+  };
+
+  struct BacklogMO {
+    MsgId messageid;
+    QDateTime time; // has to be in UTC!
+    BufferId bufferid;
+    int type;
+    int flags;
+    int senderid;
+    QString message;
+  };
+
+  struct IrcServerMO {
+    int serverid;
+    UserId userid;
+    NetworkId networkid;
+    QString hostname;
+    int port;
+    QString password;
+    bool ssl;
+    int sslversion;
+    bool useproxy;
+    int proxytype;
+    QString proxyhost;
+    int proxyport;
+    QString proxyuser;
+    QString proxypass;
+  };
+
+  struct UserSettingMO {
+    UserId userid;
+    QString settingname;
+    QByteArray settingvalue;
+  };
+
+  enum MigrationObject {
+    QuasselUser,
+    Sender,
+    Identity,
+    IdentityNick,
+    Network,
+    Buffer,
+    Backlog,
+    IrcServer,
+    UserSetting
+  };
+
+  AbstractSqlMigrator();
+  virtual ~AbstractSqlMigrator() {}
+
+  static QString migrationObject(MigrationObject moType);
+
+protected:
+  void newQuery(const QString &query, QSqlDatabase db);
+  virtual void resetQuery();
+  virtual bool prepareQuery(MigrationObject mo) = 0;
+  bool exec();
+  inline bool next() { return _query->next(); }
+  inline QVariant value(int index) { return _query->value(index); }
+  inline void bindValue(const QString &placeholder, const QVariant &val) { _query->bindValue(placeholder, val); }
+  inline void bindValue(int pos, const QVariant &val) { _query->bindValue(pos, val); }
+
+  inline QSqlError lastError() { return _query ? _query->lastError() : QSqlError(); }
+  void dumpStatus();
+  inline QString executedQuery() { return _query ? _query->executedQuery() : QString(); }
+  inline QVariantList boundValues();
+
+  virtual bool transaction() = 0;
+  virtual void rollback() = 0;
+  virtual bool commit() = 0;
+
+private:
+  QSqlQuery *_query;
 };
 
+class AbstractSqlMigrationReader : public AbstractSqlMigrator {
+public:
+  AbstractSqlMigrationReader();
+
+  virtual bool readMo(QuasselUserMO &user) = 0;
+  virtual bool readMo(IdentityMO &identity) = 0;
+  virtual bool readMo(IdentityNickMO &identityNick) = 0;
+  virtual bool readMo(NetworkMO &network) = 0;
+  virtual bool readMo(BufferMO &buffer) = 0;
+  virtual bool readMo(SenderMO &sender) = 0;
+  virtual bool readMo(BacklogMO &backlog) = 0;
+  virtual bool readMo(IrcServerMO &ircserver) = 0;
+  virtual bool readMo(UserSettingMO &userSetting) = 0;
+
+  bool migrateTo(AbstractSqlMigrationWriter *writer);
+
+private:
+  void abortMigration(const QString &errorMsg = QString());
+  bool finalizeMigration();
+
+  template<typename T> bool transferMo(MigrationObject moType, T &mo);
+
+  AbstractSqlMigrationWriter *_writer;
+};
+
+class AbstractSqlMigrationWriter : public AbstractSqlMigrator {
+public:
+  virtual bool writeMo(const QuasselUserMO &user) = 0;
+  virtual bool writeMo(const IdentityMO &identity) = 0;
+  virtual bool writeMo(const IdentityNickMO &identityNick) = 0;
+  virtual bool writeMo(const NetworkMO &network) = 0;
+  virtual bool writeMo(const BufferMO &buffer) = 0;
+  virtual bool writeMo(const SenderMO &sender) = 0;
+  virtual bool writeMo(const BacklogMO &backlog) = 0;
+  virtual bool writeMo(const IrcServerMO &ircserver) = 0;
+  virtual bool writeMo(const UserSettingMO &userSetting) = 0;
+
+  inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); }
+
+  // called after migration process
+  virtual inline bool postProcess() { return true; }
+  friend class AbstractSqlMigrationReader;
+};
 
 #endif