Fixed bug when deallocating EContact from GList.
[qwerkisync] / DBBackends / RtcomEventLoggerComponents / TriggerDisabler.cpp
diff --git a/DBBackends/RtcomEventLoggerComponents/TriggerDisabler.cpp b/DBBackends/RtcomEventLoggerComponents/TriggerDisabler.cpp
new file mode 100644 (file)
index 0000000..e7edc8e
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2011, Jamie Thompson
+ *
+ * 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 3 of the License, or (at your option) any later version.
+ *
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "TriggerDisabler.h"
+
+#include "Settings.h"
+
+#include <QtSql>
+
+#include <sqlite3.h>
+
+#include <stdexcept>
+
+static void _sqlite3ORStep(sqlite3_context *context, int numArgs, sqlite3_value **value);
+static void _sqlite3ORFinal(sqlite3_context *context);
+bool createSQLiteFunctions(const QSqlDatabase &db);
+
+using namespace DBBackends::RtcomEventLoggerComponents;
+
+TriggerDisabler::TriggerDisabler(const Settings &settings)
+       : m_Settings(settings), m_Reenabled(false)
+{
+       // Preserve default cache triggers
+       // Set up the database connection...
+       QSqlDatabase db(QSqlDatabase::addDatabase( "QSQLITE" ));
+
+       db.setDatabaseName(CurrentSettings().DBPath());
+       if ( ! db.open() )
+               throw std::runtime_error("Cannot open database: Unable to establish database connection");
+       else
+       {
+               qDebug() << "DB Opened";
+
+               QSqlQuery dbqGetTriggers(db);
+               dbqGetTriggers.setForwardOnly( true );
+
+               const char * sqlGetTriggers("SELECT name, sql FROM sqlite_master WHERE type = \"trigger\" AND name LIKE \"gc_update_ev_%\"");
+               if(dbqGetTriggers.exec(sqlGetTriggers))
+               {
+                       qDebug() << "Query OK, " << dbqGetTriggers.numRowsAffected() << " rows affected.";
+
+                       while( dbqGetTriggers.next())
+                       {
+                               QString name(dbqGetTriggers.value(0).value<QString>());
+                               QString sqlTrigger(dbqGetTriggers.value(1).value<QString>());
+
+                               qDebug() << "( " << name << ", " << sqlTrigger << " )";
+
+                               Triggers().insert(name, sqlTrigger);
+                       }
+
+                       qDebug() << Triggers().count() << " triggers found.";
+
+                       QSqlQuery dbqRemoveTriggers(db);
+                       dbqRemoveTriggers.setForwardOnly( true );
+
+                       const QString sqlRemoveTriggers("DROP TRIGGER ");
+                       foreach(QString triggerName, Triggers().keys())
+                       {
+                               qDebug() << "Executing: " << sqlRemoveTriggers + triggerName;
+                               if(dbqRemoveTriggers.exec(sqlRemoveTriggers + triggerName))
+                                       qDebug() << "Query OK, " << dbqGetTriggers.numRowsAffected() << " rows affected.";
+                               else
+                                       qDebug() << "Query failed, " << dbqGetTriggers.numRowsAffected() << " rows affected. Error: " << dbqRemoveTriggers.lastError().text();
+                       }
+               }
+               else
+               {
+                       qDebug() << "SQL EXEC Error: " << "EXEC query failed";
+                       qDebug() << "Query: " << sqlGetTriggers;
+               }
+
+               qDebug() << "Closing.";
+               db.close();
+       }
+
+       QSqlDatabase::removeDatabase("QSQLITE");
+
+       return;
+}
+
+TriggerDisabler::~TriggerDisabler()
+{
+       // Restore default cache triggers
+       if(!Reenabled())
+               Reenable();
+}
+
+void TriggerDisabler::Reenable()
+{
+       // Set up the database connection...
+       QSqlDatabase db(QSqlDatabase::addDatabase( "QSQLITE" ));
+
+       db.setDatabaseName(CurrentSettings().DBPath());
+       if (!db.open())
+               throw std::runtime_error("Cannot open database: Unable to establish database connection");
+       else
+       {
+               qDebug() << "DB Opened";
+
+               RestoreTriggers(db);
+
+               UpdateGroupCache(db);
+
+               qDebug() << "Closing DB.";
+               db.close();
+       }
+
+       QSqlDatabase::removeDatabase( "QSQLITE" );
+
+       Reenabled(true);
+}
+
+void TriggerDisabler::RestoreTriggers(QSqlDatabase &db)
+{
+       QSqlQuery dbqRestoreTriggers(db);
+       dbqRestoreTriggers.setForwardOnly( true );
+
+       foreach(QString triggerName, Triggers().keys())
+       {
+               qDebug() << "Restoring trigger " << triggerName;
+               qDebug() << "\tSQL: " << Triggers().value(triggerName);
+               if(dbqRestoreTriggers.exec(Triggers().value(triggerName)))
+                       qDebug() << "Query OK, " << dbqRestoreTriggers.numRowsAffected() << " rows affected.";
+               else
+                       qDebug() << "Query failed, " << dbqRestoreTriggers.numRowsAffected() << " rows affected. Error: " << dbqRestoreTriggers.lastError().text();
+       }
+}
+
+void TriggerDisabler::UpdateGroupCache(QSqlDatabase &db)
+{
+       const char * sqlUpdateGroupCache(
+               "INSERT OR REPLACE INTO groupcache "
+               "SELECT id, service_id, group_uid, total, readcount, mergedflags "
+               "FROM events e, "
+                       "(SELECT max(start_time) as maxdate, group_uid as maxgid, count(group_uid) as total, total(is_read) as readcount, _OR(flags) as mergedflags "
+                       "FROM events "
+                       "GROUP BY maxgid) maxresults "
+               "WHERE group_uid = maxgid AND start_time=maxresults.maxdate "
+               "GROUP BY group_uid");
+
+       QSqlQuery dbqRecalculateGroupCache(db);
+       dbqRecalculateGroupCache.setForwardOnly(true);
+
+       createSQLiteFunctions(db);
+
+       qDebug() << "Updating group cache...";
+       if(dbqRecalculateGroupCache.exec(sqlUpdateGroupCache))
+       {
+               qDebug() << "Query OK, " << dbqRecalculateGroupCache.numRowsAffected() << " rows affected.";
+
+               while(dbqRecalculateGroupCache.next())
+               {
+                       int id(dbqRecalculateGroupCache.value(0).value<int>());
+                       QString group_uid(dbqRecalculateGroupCache.value(1).value<QString>());
+                       int total(dbqRecalculateGroupCache.value(2).value<int>());
+                       int readcount(dbqRecalculateGroupCache.value(3).value<int>());
+                       int flags(dbqRecalculateGroupCache.value(4).value<int>());
+
+                       qDebug() << "( " << id << ", " << group_uid << ", " << total << ", " << readcount << ", " << flags << " )";
+               }
+       }
+       else
+       {
+               qDebug() << "SQL EXEC Error: " << "EXEC query failed. Error: " << dbqRecalculateGroupCache.lastError().text();
+               qDebug() << "Query: " << sqlUpdateGroupCache;
+       }
+}
+
+bool createSQLiteFunctions(const QSqlDatabase &db)
+{
+       // Get handle to the driver and check it is both valid and refers to SQLite3.
+       QVariant v(db.driver()->handle());
+       if (!v.isValid() || qstrcmp(v.typeName(), "sqlite3*") != 0)
+       {
+               qDebug() << "Cannot get a sqlite3 handle to the driver.";
+               return false;
+       }
+
+       // Create a handler and attach functions.
+       sqlite3 *handler(*static_cast<sqlite3**>(v.data()));
+       if (!handler)
+       {
+               qDebug() << "Cannot get a sqlite3 handler.";
+               return false;
+       }
+
+       // Check validity of the state.
+       if (!db.isValid())
+       {
+               qDebug() << "Cannot create SQLite custom functions: db object is not valid.";
+               return false;
+       }
+
+       if (!db.isOpen())
+       {
+               qDebug() << "Cannot create SQLite custom functions: db object is not open.";
+               return false;
+       }
+
+       if (sqlite3_create_function(handler, "_OR", 1, SQLITE_ANY, NULL, NULL, _sqlite3ORStep, _sqlite3ORFinal))
+               qDebug() << "Cannot create SQLite functions: sqlite3_create_function failed.";
+
+       return true;
+}
+
+static void _sqlite3ORStep(sqlite3_context *context, int, sqlite3_value **value)
+{
+       int *result((int *)sqlite3_aggregate_context(context, sizeof(int)));
+       *result |= sqlite3_value_int(*value);
+}
+
+static void _sqlite3ORFinal(sqlite3_context *context)
+{
+       sqlite3_result_int(context, *(int *)sqlite3_aggregate_context(context, sizeof(int)));
+}