summaryrefslogtreecommitdiff
path: root/libopie/pim/ocontactaccessbackend_sql.cpp
authoreilers <eilers>2003-09-22 14:31:15 (UTC)
committer eilers <eilers>2003-09-22 14:31:15 (UTC)
commit34e86ddf4f9b1045a5b730beab2d8d72e2dd4d56 (patch) (side-by-side diff)
treecee19bfcf7c8d6a24cd4aaf578bd64b38b2d0ee4 /libopie/pim/ocontactaccessbackend_sql.cpp
parentfd500184450e37c239e573adf1c12a6ff62b65f6 (diff)
downloadopie-34e86ddf4f9b1045a5b730beab2d8d72e2dd4d56.zip
opie-34e86ddf4f9b1045a5b730beab2d8d72e2dd4d56.tar.gz
opie-34e86ddf4f9b1045a5b730beab2d8d72e2dd4d56.tar.bz2
Added first experimental incarnation of sql-backend for addressbook.
Some modifications to be able to compile the todo sql-backend. A lot of changes fill follow...
Diffstat (limited to 'libopie/pim/ocontactaccessbackend_sql.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/pim/ocontactaccessbackend_sql.cpp664
1 files changed, 664 insertions, 0 deletions
diff --git a/libopie/pim/ocontactaccessbackend_sql.cpp b/libopie/pim/ocontactaccessbackend_sql.cpp
new file mode 100644
index 0000000..4afa5f3
--- a/dev/null
+++ b/libopie/pim/ocontactaccessbackend_sql.cpp
@@ -0,0 +1,664 @@
+/*
+ * SQL Backend for the OPIE-Contact Database.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2003/09/22 14:31:16 eilers
+ * Added first experimental incarnation of sql-backend for addressbook.
+ * Some modifications to be able to compile the todo sql-backend.
+ * A lot of changes fill follow...
+ *
+ */
+
+#include "ocontactaccessbackend_sql.h"
+
+#include <qarray.h>
+#include <qdatetime.h>
+#include <qstringlist.h>
+
+#include <qpe/global.h>
+#include <qpe/recordfields.h>
+
+#include <opie/ocontactfields.h>
+#include <opie/oconversion.h>
+#include <opie2/osqldriver.h>
+#include <opie2/osqlresult.h>
+#include <opie2/osqlmanager.h>
+#include <opie2/osqlquery.h>
+
+/*
+ * Implementation of used query types
+ * CREATE query
+ * LOAD query
+ * INSERT
+ * REMOVE
+ * CLEAR
+ */
+namespace {
+ /**
+ * CreateQuery for the Todolist Table
+ */
+ class CreateQuery : public OSQLQuery {
+ public:
+ CreateQuery();
+ ~CreateQuery();
+ QString query()const;
+ };
+
+ /**
+ * Clears (delete) a Table
+ */
+ class ClearQuery : public OSQLQuery {
+ public:
+ ClearQuery();
+ ~ClearQuery();
+ QString query()const;
+
+ };
+
+
+ /**
+ * LoadQuery
+ * this one queries for all uids
+ */
+ class LoadQuery : public OSQLQuery {
+ public:
+ LoadQuery();
+ ~LoadQuery();
+ QString query()const;
+ };
+
+ /**
+ * inserts/adds a OContact to the table
+ */
+ class InsertQuery : public OSQLQuery {
+ public:
+ InsertQuery(const OContact& );
+ ~InsertQuery();
+ QString query()const;
+ private:
+ OContact m_contact;
+ };
+
+
+ /**
+ * removes one from the table
+ */
+ class RemoveQuery : public OSQLQuery {
+ public:
+ RemoveQuery(int uid );
+ ~RemoveQuery();
+ QString query()const;
+ private:
+ int m_uid;
+ };
+
+ /**
+ * a find query for noncustom elements
+ */
+ class FindQuery : public OSQLQuery {
+ public:
+ FindQuery(int uid);
+ FindQuery(const QArray<int>& );
+ ~FindQuery();
+ QString query()const;
+ private:
+ QString single()const;
+ QString multi()const;
+ QArray<int> m_uids;
+ int m_uid;
+ };
+
+ /**
+ * a find query for custom elements
+ */
+ class FindCustomQuery : public OSQLQuery {
+ public:
+ FindCustomQuery(int uid);
+ FindCustomQuery(const QArray<int>& );
+ ~FindCustomQuery();
+ QString query()const;
+ private:
+ QString single()const;
+ QString multi()const;
+ QArray<int> m_uids;
+ int m_uid;
+ };
+
+
+
+ // We using three tables to store the information:
+ // 1. addressbook : It contains General information about the contact (non custom)
+ // 2. dates : Stuff like birthdays, anniversaries, etc.
+ // 3. custom_data : Not official supported entries
+ // All tables are connected by the uid of the contact.
+ // Maybe I should add a table for meta-information ?
+ CreateQuery::CreateQuery() : OSQLQuery() {}
+ CreateQuery::~CreateQuery() {}
+ QString CreateQuery::query()const {
+ QString qu;
+ qu += "create table addressbook( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id));";
+ qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );";
+// qu += "create table dates( uid PRIMARY KEY, type, day, month, year, hour, minute, second );";
+ return qu;
+ }
+
+ ClearQuery::ClearQuery()
+ : OSQLQuery() {}
+ ClearQuery::~ClearQuery() {}
+ QString ClearQuery::query()const {
+ QString qu = "drop table addressbook;";
+ qu += "drop table custom_data;";
+ qu += "drop table dates;";
+ return qu;
+ }
+
+// Distinct loading is not very fast. If I expect that every person has just
+// one (and always one) 'Last Name', I can request all uid's for existing lastnames,
+// which is faster..
+// But this may not be true for all entries, like company contacts..
+// The current AddressBook application handles this problem, but other may not.. (eilers)
+#define __USE_SUPERFAST_LOADQUERY
+
+ LoadQuery::LoadQuery() : OSQLQuery() {}
+ LoadQuery::~LoadQuery() {}
+ QString LoadQuery::query()const {
+ QString qu;
+#ifndef __USE_SUPERFAST_LOADQUERY
+ qu += "select distinct uid from addressbook";
+#else
+ qu += "select uid from addressbook where type = 'Last Name'";
+#endif
+
+ return qu;
+ }
+
+
+ InsertQuery::InsertQuery( const OContact& contact )
+ : OSQLQuery(), m_contact( contact ) {
+ }
+
+ InsertQuery::~InsertQuery() {
+ }
+
+ /*
+ * converts from a OContact to a query
+ */
+ QString InsertQuery::query()const{
+
+ // Get all information out of the contact-class
+ // Remember: The category is stored in contactMap, too !
+ QMap<int, QString> contactMap = m_contact.toMap();
+ QMap<QString, QString> customMap = m_contact.toExtraMap();
+
+ QMap<QString, QString> addressbook_db;
+
+ // Get the translation from the ID to the String
+ QMap<int, QString> transMap = OContactFields::idToUntrFields();
+
+ for( QMap<int, QString>::Iterator it = contactMap.begin();
+ it != contactMap.end(); ++it ){
+ switch ( it.key() ){
+ case Qtopia::Birthday:{
+ // These entries should stored in a special format
+ // year-month-day
+ QDate day = m_contact.birthday();
+ addressbook_db.insert( transMap[it.key()],
+ QString("%1-%2-%3")
+ .arg( day.year() )
+ .arg( day.month() )
+ .arg( day.day() ) );
+ }
+ break;
+ case Qtopia::Anniversary:{
+ // These entries should stored in a special format
+ // year-month-day
+ QDate day = m_contact.anniversary();
+ addressbook_db.insert( transMap[it.key()],
+ QString("%1-%2-%3")
+ .arg( day.year() )
+ .arg( day.month() )
+ .arg( day.day() ) );
+ }
+ break;
+ case Qtopia::AddressUid: // Ignore UID
+ break;
+ default: // Translate id to String
+ addressbook_db.insert( transMap[it.key()], it.data() );
+ break;
+ }
+
+ }
+
+ // Now convert this whole stuff into a SQL String, beginning with
+ // the addressbook table..
+ QString qu;
+ // qu += "begin transaction;";
+ int id = 0;
+ for( QMap<QString, QString>::Iterator it = addressbook_db.begin();
+ it != addressbook_db.end(); ++it ){
+ qu += "insert into addressbook VALUES("
+ + QString::number( m_contact.uid() )
+ + ","
+ + QString::number( id++ )
+ + ",'"
+ + it.key() //.latin1()
+ + "',"
+ + "0" // Priority for future enhancements
+ + ",'"
+ + it.data() //.latin1()
+ + "');";
+ }
+
+ // Now add custom data..
+ id = 0;
+ for( QMap<QString, QString>::Iterator it = customMap.begin();
+ it != customMap.end(); ++it ){
+ qu += "insert into custom_data VALUES("
+ + QString::number( m_contact.uid() )
+ + ","
+ + QString::number( id++ )
+ + ",'"
+ + it.key() //.latin1()
+ + "',"
+ + "0" // Priority for future enhancements
+ + ",'"
+ + it.data() //.latin1()
+ + "');";
+ }
+
+ // qu += "commit;";
+ qWarning("add %s", qu.latin1() );
+ return qu;
+ }
+
+
+ RemoveQuery::RemoveQuery(int uid )
+ : OSQLQuery(), m_uid( uid ) {}
+ RemoveQuery::~RemoveQuery() {}
+ QString RemoveQuery::query()const {
+ QString qu = "DELETE from addressbook where uid = "
+ + QString::number(m_uid) + ";";
+ qu += "DELETE from dates where uid = "
+ + QString::number(m_uid) + ";";
+ qu += "DELETE from custom_data where uid = "
+ + QString::number(m_uid) + ";";
+ return qu;
+ }
+
+
+
+
+ FindQuery::FindQuery(int uid)
+ : OSQLQuery(), m_uid( uid ) {
+ }
+ FindQuery::FindQuery(const QArray<int>& ints)
+ : OSQLQuery(), m_uids( ints ){
+ }
+ FindQuery::~FindQuery() {
+ }
+ QString FindQuery::query()const{
+// if ( m_uids.count() == 0 )
+ return single();
+ }
+ /*
+ else
+ return multi();
+ }
+ QString FindQuery::multi()const {
+ QString qu = "select uid, type, value from addressbook where";
+ for (uint i = 0; i < m_uids.count(); i++ ) {
+ qu += " UID = " + QString::number( m_uids[i] ) + " OR";
+ }
+ qu.remove( qu.length()-2, 2 ); // Hmmmm..
+ return qu;
+ }
+ */
+ QString FindQuery::single()const{
+ QString qu = "select uid, type, value from addressbook where uid = ";
+ qu += QString::number(m_uid);
+ return qu;
+ }
+
+
+ FindCustomQuery::FindCustomQuery(int uid)
+ : OSQLQuery(), m_uid( uid ) {
+ }
+ FindCustomQuery::FindCustomQuery(const QArray<int>& ints)
+ : OSQLQuery(), m_uids( ints ){
+ }
+ FindCustomQuery::~FindCustomQuery() {
+ }
+ QString FindCustomQuery::query()const{
+// if ( m_uids.count() == 0 )
+ return single();
+ }
+ QString FindCustomQuery::single()const{
+ QString qu = "select uid, type, value from custom_data where uid = ";
+ qu += QString::number(m_uid);
+ return qu;
+ }
+
+};
+
+
+/* --------------------------------------------------------------------------- */
+
+OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */,
+ const QString& filename ): m_changed(false)
+{
+ qWarning("C'tor OContactAccessBackend_SQL starts");
+ QTime t;
+ t.start();
+
+ /* Expecting to access the default filename if nothing else is set */
+ if ( filename.isEmpty() ){
+ m_fileName = Global::applicationFileName( "addressbook","addressbook.db" );
+ } else
+ m_fileName = filename;
+
+ // Get the standart sql-driver from the OSQLManager..
+ OSQLManager man;
+ m_driver = man.standard();
+ m_driver->setUrl( m_fileName );
+
+ load();
+
+ qWarning("C'tor OContactAccessBackend_SQL ends: %d", t.elapsed() );
+}
+
+
+bool OContactAccessBackend_SQL::load ()
+{
+ if (!m_driver->open() )
+ return false;
+
+ // Don't expect that the database exists.
+ // It is save here to create the table, even if it
+ // do exist. ( Is that correct for all databases ?? )
+ CreateQuery creat;
+ OSQLResult res = m_driver->query( &creat );
+
+ update();
+
+ return true;
+
+}
+
+bool OContactAccessBackend_SQL::reload()
+{
+ return load();
+}
+
+bool OContactAccessBackend_SQL::save()
+{
+ return m_driver->close();
+}
+
+
+void OContactAccessBackend_SQL::clear ()
+{
+ ClearQuery cle;
+ OSQLResult res = m_driver->query( &cle );
+ CreateQuery qu;
+ res = m_driver->query(&qu);
+}
+
+bool OContactAccessBackend_SQL::wasChangedExternally()
+{
+ return false;
+}
+
+QArray<int> OContactAccessBackend_SQL::allRecords() const
+{
+
+ // FIXME: Think about cute handling of changed tables..
+ // Thus, we don't have to call update here...
+ if ( m_changed )
+ ((OContactAccessBackend_SQL*)this)->update();
+
+ return m_uids;
+}
+
+bool OContactAccessBackend_SQL::add ( const OContact &newcontact )
+{
+ InsertQuery ins( newcontact );
+ OSQLResult res = m_driver->query( &ins );
+
+ if ( res.state() == OSQLResult::Failure )
+ return false;
+
+ int c = m_uids.count();
+ m_uids.resize( c+1 );
+ m_uids[c] = newcontact.uid();
+
+ return true;
+}
+
+
+bool OContactAccessBackend_SQL::remove ( int uid )
+{
+ RemoveQuery rem( uid );
+ OSQLResult res = m_driver->query(&rem );
+
+ if ( res.state() == OSQLResult::Failure )
+ return false;
+
+ m_changed = true;
+
+ return true;
+}
+
+bool OContactAccessBackend_SQL::replace ( const OContact &contact )
+{
+ if ( !remove( contact.uid() ) )
+ return false;
+
+ return add( contact );
+}
+
+
+OContact OContactAccessBackend_SQL::find ( int uid ) const
+{
+ qWarning("OContactAccessBackend_SQL::find()");
+ QTime t;
+ t.start();
+
+ OContact retContact( requestNonCustom( uid ) );
+ retContact.setExtraMap( requestCustom( uid ) );
+
+ qWarning("OContactAccessBackend_SQL::find() needed: %d", t.elapsed() );
+ return retContact;
+}
+
+
+
+QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() )
+{
+ QArray<int> nix(0);
+ return nix;
+}
+
+QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const
+{
+ QArray<int> nix(0);
+ return nix;
+}
+
+const uint OContactAccessBackend_SQL::querySettings()
+{
+ return 0;
+}
+
+bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const
+{
+ return false;
+}
+
+QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int )
+{
+ QTime t;
+ t.start();
+
+ // Not implemented..
+ QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' ";
+
+ query += "ORDER BY value ";
+ if ( !asc )
+ query += "DESC";
+
+ qWarning("sorted query is: %s", query.latin1() );
+
+ OSQLRawQuery raw( query );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success ){
+ QArray<int> empty;
+ return empty;
+ }
+
+ QArray<int> list = extractUids( res );
+
+ qWarning("sorted needed %d ms!", t.elapsed() );
+ return list;
+}
+
+
+void OContactAccessBackend_SQL::update()
+{
+ qWarning("Update starts");
+ QTime t;
+ t.start();
+
+ // Now load the database set and extract the uid's
+ // which will be held locally
+
+ LoadQuery lo;
+ OSQLResult res = m_driver->query(&lo);
+ if ( res.state() != OSQLResult::Success )
+ return;
+
+ m_uids = extractUids( res );
+
+ m_changed = false;
+
+ qWarning("Update ends %d", t.elapsed() );
+}
+
+QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const
+{
+ qWarning("extractUids");
+ QTime t;
+ t.start();
+ OSQLResultItem::ValueList list = res.results();
+ OSQLResultItem::ValueList::Iterator it;
+ QArray<int> ints(list.count() );
+ qWarning(" count = %d", list.count() );
+
+ int i = 0;
+ for (it = list.begin(); it != list.end(); ++it ) {
+ ints[i] = (*it).data("uid").toInt();
+ i++;
+ }
+ qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() );
+
+ return ints;
+
+}
+
+QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const
+{
+ QTime t;
+ t.start();
+
+ QMap<int, QString> nonCustomMap;
+
+ int t2needed = 0;
+ QTime t2;
+ t2.start();
+ FindQuery query( uid );
+ OSQLResult res_noncustom = m_driver->query( &query );
+ t2needed = t2.elapsed();
+
+ if ( res_noncustom.state() == OSQLResult::Failure ) {
+ qWarning("OSQLResult::Failure in find query !!");
+ QMap<int, QString> empty;
+ return empty;
+ }
+
+ int t3needed = 0;
+ QTime t3;
+ t3.start();
+ QMap<QString, int> translateMap = OContactFields::untrFieldsToId();
+
+ OSQLResultItem::ValueList list = res_noncustom.results();
+ OSQLResultItem::ValueList::Iterator it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ if ( (*it).data("type") != "" ){
+ int typeId = translateMap[(*it).data( "type" )];
+ switch( typeId ){
+ case Qtopia::Birthday:
+ case Qtopia::Anniversary:{
+ // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
+ QStringList list = QStringList::split( '-', (*it).data( "value" ) );
+ QStringList::Iterator lit = list.begin();
+ int year = (*lit).toInt();
+ qWarning("1. %s", (*lit).latin1());
+ int month = (*(++lit)).toInt();
+ qWarning("2. %s", (*lit).latin1());
+ int day = (*(++lit)).toInt();
+ qWarning("3. %s", (*lit).latin1());
+ qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day );
+ QDate date( year, month, day );
+ nonCustomMap.insert( typeId, OConversion::dateToString( date ) );
+ }
+ break;
+ default:
+ nonCustomMap.insert( typeId,
+ (*it).data( "value" ) );
+ }
+ }
+ }
+ // Add UID to Map..
+ nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) );
+ t3needed = t3.elapsed();
+
+ qWarning("RequestNonCustom needed: ins:%d, query: %d, mapping: %d", t.elapsed(), t2needed, t3needed );
+ return nonCustomMap;
+}
+
+QMap<QString, QString> OContactAccessBackend_SQL::requestCustom( int uid ) const
+{
+ QTime t;
+ t.start();
+
+ QMap<QString, QString> customMap;
+
+ FindCustomQuery query( uid );
+ OSQLResult res_custom = m_driver->query( &query );
+
+ if ( res_custom.state() == OSQLResult::Failure ) {
+ qWarning("OSQLResult::Failure in find query !!");
+ QMap<QString, QString> empty;
+ return empty;
+ }
+
+ OSQLResultItem::ValueList list = res_custom.results();
+ OSQLResultItem::ValueList::Iterator it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ customMap.insert( (*it).data( "type" ), (*it).data( "value" ) );
+ }
+
+ qWarning("RequestCustom needed: %d", t.elapsed() );
+ return customMap;
+}