From 34e86ddf4f9b1045a5b730beab2d8d72e2dd4d56 Mon Sep 17 00:00:00 2001 From: eilers Date: Mon, 22 Sep 2003 14:31:15 +0000 Subject: 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... --- (limited to 'libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp') diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp new file mode 100644 index 0000000..4afa5f3 --- a/dev/null +++ b/libopie2/opiepim/backend/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 +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * 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& ); + ~FindQuery(); + QString query()const; + private: + QString single()const; + QString multi()const; + QArray m_uids; + int m_uid; + }; + + /** + * a find query for custom elements + */ + class FindCustomQuery : public OSQLQuery { + public: + FindCustomQuery(int uid); + FindCustomQuery(const QArray& ); + ~FindCustomQuery(); + QString query()const; + private: + QString single()const; + QString multi()const; + QArray 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 contactMap = m_contact.toMap(); + QMap customMap = m_contact.toExtraMap(); + + QMap addressbook_db; + + // Get the translation from the ID to the String + QMap transMap = OContactFields::idToUntrFields(); + + for( QMap::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::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::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& 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& 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 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 OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ) +{ + QArray nix(0); + return nix; +} + +QArray OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const +{ + QArray nix(0); + return nix; +} + +const uint OContactAccessBackend_SQL::querySettings() +{ + return 0; +} + +bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const +{ + return false; +} + +QArray 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 empty; + return empty; + } + + QArray 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 OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const +{ + qWarning("extractUids"); + QTime t; + t.start(); + OSQLResultItem::ValueList list = res.results(); + OSQLResultItem::ValueList::Iterator it; + QArray 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 OContactAccessBackend_SQL::requestNonCustom( int uid ) const +{ + QTime t; + t.start(); + + QMap 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 empty; + return empty; + } + + int t3needed = 0; + QTime t3; + t3.start(); + QMap 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 OContactAccessBackend_SQL::requestCustom( int uid ) const +{ + QTime t; + t.start(); + + QMap customMap; + + FindCustomQuery query( uid ); + OSQLResult res_custom = m_driver->query( &query ); + + if ( res_custom.state() == OSQLResult::Failure ) { + qWarning("OSQLResult::Failure in find query !!"); + QMap 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; +} -- cgit v0.9.0.2