Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ocontactaccessbackend_sql.cpp

Go to the documentation of this file.
00001 /*
00002  * SQL Backend for the OPIE-Contact Database.
00003  *
00004  * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
00005  *
00006  * =====================================================================
00007  *      This program is free software; you can redistribute it and/or
00008  *      modify it under the terms of the GNU Library General Public
00009  *      License as published by the Free Software Foundation; either
00010  *      version 2 of the License, or (at your option) any later version.
00011  * =====================================================================
00012  * =====================================================================
00013  * Version: $Id: ocontactaccessbackend_sql.cpp,v 1.1 2004/11/16 21:46:07 mickeyl Exp $
00014  * =====================================================================
00015  * History:
00016  * $Log: ocontactaccessbackend_sql.cpp,v $
00017  * Revision 1.1  2004/11/16 21:46:07  mickeyl
00018  * libopie1 goes into unsupported
00019  *
00020  * Revision 1.5  2004/03/14 13:50:35  alwin
00021  * namespace correction
00022  *
00023  * Revision 1.4  2003/12/22 10:19:26  eilers
00024  * Finishing implementation of sql-backend for datebook. But I have to
00025  * port the PIM datebook application to use it, before I could debug the
00026  * whole stuff.
00027  * Thus, PIM-Database backend is finished, but highly experimental. And some
00028  * parts are still generic. For instance, the "queryByExample()" methods are
00029  * not (or not fully) implemented. Todo: custom-entries not stored.
00030  * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular
00031  * expression search in the database, which is not supported by sqlite !
00032  * Therefore we need either an extended sqlite or a workaround which would
00033  * be very slow and memory consuming..
00034  *
00035  * Revision 1.3  2003/12/08 15:18:10  eilers
00036  * Committing unfinished sql implementation before merging to libopie2 starts..
00037  *
00038  * Revision 1.2  2003/09/29 07:44:26  eilers
00039  * Improvement of PIM-SQL Databases, but search queries are still limited.
00040  * Addressbook: Changed table layout. Now, we just need 1/3 of disk-space.
00041  * Todo: Started to add new attributes. Some type conversions missing.
00042  *
00043  * Revision 1.1  2003/09/22 14:31:16  eilers
00044  * Added first experimental incarnation of sql-backend for addressbook.
00045  * Some modifications to be able to compile the todo sql-backend.
00046  * A lot of changes fill follow...
00047  *
00048  */
00049 
00050 #include "ocontactaccessbackend_sql.h"
00051 
00052 #include <qarray.h>
00053 #include <qdatetime.h>
00054 #include <qstringlist.h>
00055 
00056 #include <qpe/global.h>
00057 #include <qpe/recordfields.h>
00058 
00059 #include <opie/ocontactfields.h>
00060 #include <opie/oconversion.h>
00061 #include <opie2/osqldriver.h>
00062 #include <opie2/osqlresult.h>
00063 #include <opie2/osqlmanager.h>
00064 #include <opie2/osqlquery.h>
00065 
00066 using namespace Opie::DB;
00067 
00068 
00069 // If defined, we use a horizontal table ( uid, attr1, attr2, attr3, ..., attrn ) instead
00070 // vertical like "uid, type, value".
00071 // DON'T DEACTIVATE THIS DEFINE IN PRODUCTIVE ENVIRONMENTS !!
00072 #define __STORE_HORIZONTAL_
00073 
00074 // Distinct loading is not very fast. If I expect that every person has just
00075 // one (and always one) 'Last Name', I can request all uid's for existing lastnames, 
00076 // which is faster..
00077 // But this may not be true for all entries, like company contacts..
00078 // The current AddressBook application handles this problem, but other may not.. (eilers)
00079 #define __USE_SUPERFAST_LOADQUERY
00080 
00081 
00082 /*
00083  * Implementation of used query types
00084  * CREATE query
00085  * LOAD query
00086  * INSERT
00087  * REMOVE
00088  * CLEAR
00089  */
00090 namespace {
00094         class CreateQuery : public OSQLQuery {
00095         public:
00096                 CreateQuery();
00097                 ~CreateQuery();
00098                 QString query()const;
00099         };
00100         
00104         class ClearQuery : public OSQLQuery {
00105         public:
00106                 ClearQuery();
00107                 ~ClearQuery();
00108                 QString query()const;
00109                 
00110         };
00111         
00112 
00117         class LoadQuery : public OSQLQuery {
00118         public:
00119                 LoadQuery();
00120                 ~LoadQuery();
00121                 QString query()const;
00122         };
00123         
00127         class InsertQuery : public OSQLQuery {
00128         public:
00129                 InsertQuery(const OContact& );
00130                 ~InsertQuery();
00131                 QString query()const;
00132         private:
00133                 OContact m_contact;
00134         };
00135         
00136 
00140         class RemoveQuery : public OSQLQuery {
00141         public:
00142                 RemoveQuery(int uid );
00143                 ~RemoveQuery();
00144                 QString query()const;
00145         private:
00146                 int m_uid;
00147         };
00148         
00152         class FindQuery : public OSQLQuery {
00153         public:
00154                 FindQuery(int uid);
00155                 FindQuery(const QArray<int>& );
00156                 ~FindQuery();
00157                 QString query()const;
00158         private:
00159                 QString single()const;
00160                 QString multi()const;
00161                 QArray<int> m_uids;
00162                 int m_uid;
00163         };
00164 
00168         class FindCustomQuery : public OSQLQuery {
00169         public:
00170                 FindCustomQuery(int uid);
00171                 FindCustomQuery(const QArray<int>& );
00172                 ~FindCustomQuery();
00173                 QString query()const;
00174         private:
00175                 QString single()const;
00176                 QString multi()const;
00177                 QArray<int> m_uids;
00178                 int m_uid;
00179         };
00180         
00181 
00182 
00183         // We using three tables to store the information:
00184         // 1. addressbook  : It contains General information about the contact (non custom)
00185         // 2. custom_data  : Not official supported entries
00186         // All tables are connected by the uid of the contact.
00187         // Maybe I should add a table for meta-information ? 
00188         CreateQuery::CreateQuery() : OSQLQuery() {}
00189         CreateQuery::~CreateQuery() {}
00190         QString CreateQuery::query()const {
00191                 QString qu;
00192 #ifdef __STORE_HORIZONTAL_
00193 
00194                 qu += "create table addressbook( uid PRIMARY KEY ";
00195 
00196                 QStringList fieldList = OContactFields::untrfields( false );
00197                 for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
00198                         qu += QString( ",\"%1\" VARCHAR(10)" ).arg( *it );
00199                 }
00200                 qu += " );";
00201                 
00202                 qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );";
00203 
00204 #else
00205 
00206                 qu += "create table addressbook( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id));";
00207                 qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );";
00208 //              qu += "create table dates( uid PRIMARY KEY, type, day, month, year, hour, minute, second );";
00209 
00210 #endif // __STORE_HORIZONTAL_
00211                 return qu;
00212         }
00213         
00214         ClearQuery::ClearQuery()
00215                 : OSQLQuery() {}
00216         ClearQuery::~ClearQuery() {}
00217         QString ClearQuery::query()const {
00218                 QString qu = "drop table addressbook;";
00219                 qu += "drop table custom_data;";
00220 //              qu += "drop table dates;";
00221                 return qu;
00222         }
00223 
00224 
00225         LoadQuery::LoadQuery() : OSQLQuery() {}
00226         LoadQuery::~LoadQuery() {}
00227         QString LoadQuery::query()const {
00228                 QString qu;
00229 #ifdef __STORE_HORIZONTAL_
00230                 qu += "select uid from addressbook";
00231 #else
00232 #  ifndef __USE_SUPERFAST_LOADQUERY 
00233                 qu += "select distinct uid from addressbook";
00234 #  else
00235                 qu += "select uid from addressbook where type = 'Last Name'";
00236 #  endif // __USE_SUPERFAST_LOADQUERY 
00237 #endif // __STORE_HORIZONTAL_
00238                 
00239                 return qu;
00240         }
00241         
00242 
00243         InsertQuery::InsertQuery( const OContact& contact )
00244                 : OSQLQuery(), m_contact( contact ) {
00245         }
00246 
00247         InsertQuery::~InsertQuery() {
00248         }
00249 
00250         /*
00251          * converts from a OContact to a query
00252          */
00253         QString InsertQuery::query()const{
00254 
00255 #ifdef __STORE_HORIZONTAL_
00256                 QString qu;
00257                 qu  += "insert into addressbook VALUES( " + 
00258                         QString::number( m_contact.uid() );
00259 
00260                 // Get all information out of the contact-class
00261                 // Remember: The category is stored in contactMap, too ! 
00262                 QMap<int, QString> contactMap = m_contact.toMap();
00263                 
00264                 QStringList fieldList = OContactFields::untrfields( false );
00265                 QMap<QString, int> translate = OContactFields::untrFieldsToId();
00266                 for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
00267                         // Convert Column-String to Id and get value for this id..
00268                         // Hmmm.. Maybe not very cute solution..
00269                         int id = translate[*it];
00270                         switch ( id ){
00271                         case Qtopia::Birthday:{
00272                                 // These entries should stored in a special format
00273                                 // year-month-day
00274                                 QDate day = m_contact.birthday();
00275                                 if ( day.isValid() ){
00276                                         qu += QString(",\"%1-%2-%3\"")
00277                                                 .arg( day.year() )
00278                                                 .arg( day.month() )
00279                                                 .arg( day.day() );
00280                                 } else {
00281                                         qu += ",\"\"";
00282                                 }
00283                         }
00284                                 break;
00285                         case Qtopia::Anniversary:{
00286                                 // These entries should stored in a special format
00287                                 // year-month-day
00288                                 QDate day = m_contact.anniversary();
00289                                 if ( day.isValid() ){
00290                                         qu += QString(",\"%1-%2-%3\"")
00291                                                 .arg( day.year() )
00292                                                 .arg( day.month() )
00293                                                 .arg( day.day() );
00294                                 } else {
00295                                         qu += ",\"\"";
00296                                 }
00297                         }
00298                                 break;
00299 
00300                         default:
00301                                 qu += QString( ",\"%1\"" ).arg( contactMap[id] );
00302                         }
00303                 }
00304                 qu += " );";
00305 
00306                         
00307 #else
00308                 // Get all information out of the contact-class
00309                 // Remember: The category is stored in contactMap, too ! 
00310                 QMap<int, QString> contactMap = m_contact.toMap();
00311                 
00312                 QMap<QString, QString> addressbook_db;
00313                 
00314                 // Get the translation from the ID to the String
00315                 QMap<int, QString> transMap = OContactFields::idToUntrFields();
00316                 
00317                 for( QMap<int, QString>::Iterator it = contactMap.begin(); 
00318                      it != contactMap.end(); ++it ){
00319                         switch ( it.key() ){
00320                         case Qtopia::Birthday:{
00321                                 // These entries should stored in a special format
00322                                 // year-month-day
00323                                 QDate day = m_contact.birthday();
00324                                 addressbook_db.insert( transMap[it.key()], 
00325                                                        QString("%1-%2-%3")
00326                                                        .arg( day.year() )
00327                                                        .arg( day.month() )
00328                                                        .arg( day.day() ) );
00329                         }
00330                                 break;
00331                         case Qtopia::Anniversary:{
00332                                 // These entries should stored in a special format
00333                                 // year-month-day
00334                                 QDate day = m_contact.anniversary();
00335                                 addressbook_db.insert( transMap[it.key()], 
00336                                                        QString("%1-%2-%3")
00337                                                        .arg( day.year() )
00338                                                        .arg( day.month() )
00339                                                        .arg( day.day() ) );
00340                         }
00341                                 break;
00342                         case Qtopia::AddressUid: // Ignore UID
00343                                 break;
00344                         default: // Translate id to String
00345                                 addressbook_db.insert( transMap[it.key()], it.data() );
00346                                 break;
00347                         }
00348                 
00349                 }
00350                 
00351                 // Now convert this whole stuff into a SQL String, beginning with
00352                 // the addressbook table..
00353                 QString qu;
00354                 // qu  += "begin transaction;";
00355                 int id = 0;
00356                 for( QMap<QString, QString>::Iterator it = addressbook_db.begin(); 
00357                      it != addressbook_db.end(); ++it ){
00358                         qu  += "insert into addressbook VALUES(" 
00359                                 +  QString::number( m_contact.uid() )
00360                                 + ","
00361                                 +  QString::number( id++ ) 
00362                                 + ",'" 
00363                                 + it.key() //.latin1()
00364                                 + "',"
00365                                 + "0"  // Priority for future enhancements
00366                                 + ",'" 
00367                                 + it.data()  //.latin1()
00368                                 + "');";
00369                 }
00370 
00371 #endif  //__STORE_HORIZONTAL_   
00372                 // Now add custom data..
00373 #ifdef __STORE_HORIZONTAL_
00374                 int id = 0;
00375 #endif
00376                 id = 0;
00377                 QMap<QString, QString> customMap = m_contact.toExtraMap();
00378                 for( QMap<QString, QString>::Iterator it = customMap.begin(); 
00379                      it != customMap.end(); ++it ){
00380                         qu  += "insert into custom_data VALUES(" 
00381                                 +  QString::number( m_contact.uid() )
00382                                 + ","
00383                                 +  QString::number( id++ ) 
00384                                 + ",'" 
00385                                 + it.key() //.latin1()
00386                                 + "',"
00387                                 + "0" // Priority for future enhancements
00388                                 + ",'" 
00389                                 + it.data() //.latin1()
00390                                 + "');";
00391                 }               
00392                 // qu  += "commit;";
00393                 qWarning("add %s", qu.latin1() );
00394                 return qu;
00395         }
00396         
00397 
00398         RemoveQuery::RemoveQuery(int uid )
00399                 : OSQLQuery(), m_uid( uid ) {}
00400         RemoveQuery::~RemoveQuery() {}
00401         QString RemoveQuery::query()const {
00402                 QString qu = "DELETE from addressbook where uid = " 
00403                         + QString::number(m_uid) + ";";
00404                 qu += "DELETE from custom_data where uid = " 
00405                         + QString::number(m_uid) + ";";
00406                 return qu;
00407         }
00408         
00409 
00410         
00411 
00412         FindQuery::FindQuery(int uid)
00413                 : OSQLQuery(), m_uid( uid ) {
00414         }
00415         FindQuery::FindQuery(const QArray<int>& ints)
00416                 : OSQLQuery(), m_uids( ints ){
00417         }
00418         FindQuery::~FindQuery() {
00419         }
00420         QString FindQuery::query()const{
00421 //              if ( m_uids.count() == 0 )
00422                 return single();
00423         }
00424         /*
00425           else
00426                         return multi();
00427                         }
00428         QString FindQuery::multi()const {
00429                 QString qu = "select uid, type, value from addressbook where";
00430                 for (uint i = 0; i < m_uids.count(); i++ ) {
00431                         qu += " UID = " + QString::number( m_uids[i] ) + " OR";
00432                 }
00433                 qu.remove( qu.length()-2, 2 ); // Hmmmm.. 
00434                 return qu;
00435         }
00436         */
00437 #ifdef __STORE_HORIZONTAL_
00438         QString FindQuery::single()const{
00439                 QString qu = "select *";
00440                 qu += " from addressbook where uid = " + QString::number(m_uid);
00441 
00442                 // qWarning("find query: %s", qu.latin1() );
00443                 return qu;
00444         }
00445 #else
00446         QString FindQuery::single()const{
00447                 QString qu = "select uid, type, value from addressbook where uid = ";
00448                 qu += QString::number(m_uid);
00449                 return qu;
00450         }
00451 #endif
00452 
00453 
00454         FindCustomQuery::FindCustomQuery(int uid)
00455                 : OSQLQuery(), m_uid( uid ) {
00456         }
00457         FindCustomQuery::FindCustomQuery(const QArray<int>& ints)
00458                 : OSQLQuery(), m_uids( ints ){
00459         }
00460         FindCustomQuery::~FindCustomQuery() {
00461         }
00462         QString FindCustomQuery::query()const{
00463 //              if ( m_uids.count() == 0 )
00464                         return single();
00465         }
00466         QString FindCustomQuery::single()const{
00467                 QString qu = "select uid, type, value from custom_data where uid = ";
00468                 qu += QString::number(m_uid);
00469                 return qu;
00470         }
00471 
00472 };
00473 
00474 
00475 /* --------------------------------------------------------------------------- */
00476 
00477 OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */, 
00478                                                        const QString& filename ): 
00479         OContactAccessBackend(), m_changed(false), m_driver( NULL )
00480 {
00481         qWarning("C'tor OContactAccessBackend_SQL starts");
00482         QTime t;
00483         t.start();
00484 
00485         /* Expecting to access the default filename if nothing else is set */
00486         if ( filename.isEmpty() ){
00487                 m_fileName = Global::applicationFileName( "addressbook","addressbook.db" );
00488         } else
00489                 m_fileName = filename;
00490 
00491         // Get the standart sql-driver from the OSQLManager..
00492         OSQLManager man;
00493         m_driver = man.standard();
00494         m_driver->setUrl( m_fileName ); 
00495 
00496         load();
00497 
00498         qWarning("C'tor OContactAccessBackend_SQL ends: %d ms", t.elapsed() );
00499 }
00500 
00501 OContactAccessBackend_SQL::~OContactAccessBackend_SQL ()
00502 {
00503         if( m_driver )
00504                 delete m_driver;
00505 }
00506 
00507 bool OContactAccessBackend_SQL::load ()
00508 {
00509         if (!m_driver->open() )
00510                 return false;
00511 
00512         // Don't expect that the database exists.
00513         // It is save here to create the table, even if it
00514         // do exist. ( Is that correct for all databases ?? )
00515         CreateQuery creat;
00516         OSQLResult res = m_driver->query( &creat );
00517 
00518         update();
00519 
00520         return true;
00521 
00522 }
00523 
00524 bool OContactAccessBackend_SQL::reload()
00525 {
00526         return load();
00527 }
00528 
00529 bool OContactAccessBackend_SQL::save()
00530 {
00531         return m_driver->close();  // Shouldn't m_driver->sync be better than close ? (eilers)
00532 }
00533 
00534 
00535 void OContactAccessBackend_SQL::clear ()
00536 {
00537         ClearQuery cle;
00538         OSQLResult res = m_driver->query( &cle );
00539 
00540         reload();
00541 }
00542 
00543 bool OContactAccessBackend_SQL::wasChangedExternally()
00544 {
00545         return false;
00546 }
00547 
00548 QArray<int> OContactAccessBackend_SQL::allRecords() const
00549 {
00550 
00551         // FIXME: Think about cute handling of changed tables..
00552         // Thus, we don't have to call update here...
00553         if ( m_changed )  
00554                 ((OContactAccessBackend_SQL*)this)->update();
00555         
00556         return m_uids;
00557 }
00558 
00559 bool OContactAccessBackend_SQL::add ( const OContact &newcontact )
00560 {
00561         InsertQuery ins( newcontact );
00562         OSQLResult res = m_driver->query( &ins );
00563 
00564         if ( res.state() == OSQLResult::Failure )
00565                 return false;
00566 
00567         int c = m_uids.count();
00568         m_uids.resize( c+1 );
00569         m_uids[c] = newcontact.uid();
00570         
00571         return true;
00572 }
00573 
00574 
00575 bool OContactAccessBackend_SQL::remove ( int uid )
00576 {
00577         RemoveQuery rem( uid );
00578         OSQLResult res = m_driver->query(&rem );
00579 
00580         if ( res.state() == OSQLResult::Failure )
00581                 return false;
00582 
00583         m_changed = true;
00584 
00585         return true;
00586 }
00587 
00588 bool OContactAccessBackend_SQL::replace ( const OContact &contact )
00589 {
00590         if ( !remove( contact.uid() ) )
00591                 return false;
00592         
00593         return add( contact );
00594 }
00595 
00596 
00597 OContact OContactAccessBackend_SQL::find ( int uid ) const
00598 {
00599         qWarning("OContactAccessBackend_SQL::find()");
00600         QTime t;
00601         t.start();
00602 
00603         OContact retContact( requestNonCustom( uid ) );
00604         retContact.setExtraMap( requestCustom( uid ) );
00605 
00606         qWarning("OContactAccessBackend_SQL::find() needed: %d ms", t.elapsed() );
00607         return retContact;
00608 }
00609 
00610 
00611 
00612 QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() )
00613 {
00614         QString qu = "SELECT uid FROM addressbook WHERE";
00615 
00616         QMap<int, QString> queryFields = query.toMap();
00617         QStringList fieldList = OContactFields::untrfields( false );
00618         QMap<QString, int> translate = OContactFields::untrFieldsToId();
00619 
00620         // Convert every filled field to a SQL-Query
00621         bool isAnyFieldSelected = false;
00622         for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
00623                 int id = translate[*it];
00624                 QString queryStr = queryFields[id];
00625                 if ( !queryStr.isEmpty() ){
00626                         isAnyFieldSelected = true;
00627                         switch( id ){
00628                         default:
00629                                 // Switching between case sensitive and insensitive...
00630                                 // LIKE is not case sensitive, GLOB is case sensitive
00631                                 // Do exist a better solution to switch this ?
00632                                 if ( settings & OContactAccess::IgnoreCase )
00633                                         qu += "(\"" + *it + "\"" + " LIKE " + "'" 
00634                                                 + queryStr.replace(QRegExp("\\*"),"%") + "'" + ") AND "; 
00635                                 else
00636                                         qu += "(\"" + *it + "\"" + " GLOB " + "'" 
00637                                                 + queryStr + "'" + ") AND "; 
00638                                         
00639                         }
00640                 }
00641         }
00642         // Skip trailing "AND"
00643         if ( isAnyFieldSelected )
00644                 qu = qu.left( qu.length() - 4 );
00645 
00646         qWarning( "queryByExample query: %s", qu.latin1() );
00647 
00648         // Execute query and return the received uid's
00649         OSQLRawQuery raw( qu );
00650         OSQLResult res = m_driver->query( &raw );
00651         if ( res.state() != OSQLResult::Success ){
00652                 QArray<int> empty;
00653                 return empty;
00654         }
00655 
00656         QArray<int> list = extractUids( res );
00657 
00658         return list;            
00659 }
00660 
00661 QArray<int> OContactAccessBackend_SQL::matchRegexp(  const QRegExp &r ) const
00662 {
00663         QArray<int> nix(0);
00664         return nix;
00665 }
00666 
00667 const uint OContactAccessBackend_SQL::querySettings()
00668 {
00669         return OContactAccess::IgnoreCase 
00670                 || OContactAccess::WildCards;
00671 }
00672 
00673 bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const
00674 {
00675         /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
00676          * may be added with any of the other settings. IgnoreCase should never used alone.
00677          * Wildcards, RegExp, ExactMatch should never used at the same time...
00678          */
00679 
00680         // Step 1: Check whether the given settings are supported by this backend
00681         if ( ( querySettings & ( 
00682                                 OContactAccess::IgnoreCase
00683                                 | OContactAccess::WildCards
00684 //                              | OContactAccess::DateDiff
00685 //                              | OContactAccess::DateYear
00686 //                              | OContactAccess::DateMonth
00687 //                              | OContactAccess::DateDay
00688 //                              | OContactAccess::RegExp
00689 //                              | OContactAccess::ExactMatch
00690                                ) ) != querySettings )
00691                 return false;
00692 
00693         // Step 2: Check whether the given combinations are ok..
00694 
00695         // IngoreCase alone is invalid
00696         if ( querySettings == OContactAccess::IgnoreCase )
00697                 return false;
00698 
00699         // WildCards, RegExp and ExactMatch should never used at the same time 
00700         switch ( querySettings & ~( OContactAccess::IgnoreCase
00701                                     | OContactAccess::DateDiff
00702                                     | OContactAccess::DateYear
00703                                     | OContactAccess::DateMonth
00704                                     | OContactAccess::DateDay
00705                                     )
00706                  ){
00707         case OContactAccess::RegExp:
00708                 return ( true );
00709         case OContactAccess::WildCards:
00710                 return ( true );
00711         case OContactAccess::ExactMatch:
00712                 return ( true );
00713         case 0: // one of the upper removed bits were set..
00714                 return ( true );
00715         default:
00716                 return ( false );
00717         }
00718 
00719 }
00720 
00721 QArray<int> OContactAccessBackend_SQL::sorted( bool asc,  int , int ,  int )
00722 {
00723         QTime t;
00724         t.start();
00725 
00726 #ifdef __STORE_HORIZONTAL_
00727         QString query = "SELECT uid FROM addressbook ";
00728         query += "ORDER BY \"Last Name\" ";
00729 #else
00730         QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' ";
00731         query += "ORDER BY upper( value )";
00732 #endif
00733 
00734         if ( !asc )
00735                 query += "DESC";
00736 
00737         // qWarning("sorted query is: %s", query.latin1() ); 
00738 
00739         OSQLRawQuery raw( query );
00740         OSQLResult res = m_driver->query( &raw );
00741         if ( res.state() != OSQLResult::Success ){
00742                 QArray<int> empty;
00743                 return empty;
00744         }
00745 
00746         QArray<int> list = extractUids( res );
00747 
00748         qWarning("sorted needed %d ms!", t.elapsed() );
00749         return list;
00750 }
00751 
00752 
00753 void OContactAccessBackend_SQL::update()
00754 {
00755         qWarning("Update starts");
00756         QTime t;
00757         t.start();
00758 
00759         // Now load the database set and extract the uid's
00760         // which will be held locally
00761 
00762         LoadQuery lo;
00763         OSQLResult res = m_driver->query(&lo);
00764         if ( res.state() != OSQLResult::Success )
00765                 return;
00766 
00767         m_uids = extractUids( res );
00768 
00769         m_changed = false;
00770 
00771         qWarning("Update ends %d ms", t.elapsed() );
00772 }
00773 
00774 QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const
00775 {
00776         qWarning("extractUids");
00777         QTime t;
00778         t.start();
00779         OSQLResultItem::ValueList list = res.results();
00780         OSQLResultItem::ValueList::Iterator it;
00781         QArray<int> ints(list.count() );
00782         qWarning(" count = %d", list.count() );
00783 
00784         int i = 0;
00785         for (it = list.begin(); it != list.end(); ++it ) {
00786                 ints[i] =  (*it).data("uid").toInt();
00787                 i++;
00788         }
00789         qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() );
00790 
00791         return ints;
00792 
00793 }
00794 
00795 #ifdef __STORE_HORIZONTAL_
00796 QMap<int, QString>  OContactAccessBackend_SQL::requestNonCustom( int uid ) const
00797 {
00798         QTime t;
00799         t.start();
00800 
00801         QMap<int, QString> nonCustomMap;
00802         
00803         int t2needed = 0;
00804         int t3needed = 0;
00805         QTime t2;
00806         t2.start();
00807         FindQuery query( uid );
00808         OSQLResult res_noncustom = m_driver->query( &query );
00809         t2needed = t2.elapsed();
00810 
00811         OSQLResultItem resItem = res_noncustom.first();
00812 
00813         QTime t3;
00814         t3.start();
00815         // Now loop through all columns
00816         QStringList fieldList = OContactFields::untrfields( false );
00817         QMap<QString, int> translate = OContactFields::untrFieldsToId();
00818         for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
00819                 // Get data for the selected column and store it with the
00820                 // corresponding id into the map..
00821 
00822                 int id =  translate[*it];
00823                 QString value = resItem.data( (*it) );
00824                 
00825                 // qWarning("Reading %s... found: %s", (*it).latin1(), value.latin1() );
00826 
00827                 switch( id ){
00828                 case Qtopia::Birthday:
00829                 case Qtopia::Anniversary:{
00830                         // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
00831                         QStringList list = QStringList::split( '-', value );
00832                         QStringList::Iterator lit = list.begin();
00833                         int year  = (*lit).toInt();
00834                         int month = (*(++lit)).toInt();
00835                         int day   = (*(++lit)).toInt();
00836                         if ( ( day != 0 ) && ( month != 0 ) && ( year != 0 ) ){
00837                              QDate date( year, month, day );
00838                              nonCustomMap.insert( id, OConversion::dateToString( date ) );
00839                         }
00840                 }
00841                         break;
00842                 case Qtopia::AddressCategory:
00843                         qWarning("Category is: %s", value.latin1() );
00844                 default:
00845                         nonCustomMap.insert( id, value );
00846                 }
00847         }
00848 
00849         // First insert uid
00850         nonCustomMap.insert( Qtopia::AddressUid, resItem.data( "uid" ) ); 
00851         t3needed = t3.elapsed();
00852 
00853         // qWarning("Adding UID: %s", resItem.data( "uid" ).latin1() );
00854         qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", 
00855                  t.elapsed(), t2needed, t3needed  );
00856 
00857         return nonCustomMap;
00858 }
00859 #else
00860 
00861 QMap<int, QString>  OContactAccessBackend_SQL::requestNonCustom( int uid ) const
00862 {
00863         QTime t;
00864         t.start();
00865 
00866         QMap<int, QString> nonCustomMap;
00867         
00868         int t2needed = 0;
00869         QTime t2;
00870         t2.start();
00871         FindQuery query( uid );
00872         OSQLResult res_noncustom = m_driver->query( &query );
00873         t2needed = t2.elapsed();
00874 
00875         if ( res_noncustom.state() == OSQLResult::Failure ) {
00876                 qWarning("OSQLResult::Failure in find query !!");
00877                 QMap<int, QString> empty;
00878                 return empty;
00879         }       
00880 
00881         int t3needed = 0;
00882         QTime t3;
00883         t3.start();
00884         QMap<QString, int> translateMap = OContactFields::untrFieldsToId();
00885 
00886         OSQLResultItem::ValueList list = res_noncustom.results();
00887         OSQLResultItem::ValueList::Iterator it = list.begin();
00888         for ( ; it != list.end(); ++it ) {
00889                 if ( (*it).data("type") != "" ){
00890                         int typeId = translateMap[(*it).data( "type" )];
00891                         switch( typeId ){
00892                         case Qtopia::Birthday:
00893                         case Qtopia::Anniversary:{
00894                                 // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
00895                                 QStringList list = QStringList::split( '-', (*it).data( "value" ) );
00896                                 QStringList::Iterator lit = list.begin();
00897                                 int year  = (*lit).toInt();
00898                                 qWarning("1. %s", (*lit).latin1());
00899                                 int month = (*(++lit)).toInt();
00900                                 qWarning("2. %s", (*lit).latin1());
00901                                 int day   = (*(++lit)).toInt();
00902                                 qWarning("3. %s", (*lit).latin1());
00903                                 qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day );
00904                                 QDate date( year, month, day );
00905                                 nonCustomMap.insert( typeId, OConversion::dateToString( date ) );
00906                         }
00907                                 break;
00908                         default:
00909                                 nonCustomMap.insert( typeId, 
00910                                                      (*it).data( "value" ) );
00911                         }
00912                 }
00913         }
00914         // Add UID to Map..
00915         nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) );
00916         t3needed = t3.elapsed();
00917 
00918         qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", t.elapsed(), t2needed, t3needed  );
00919         return nonCustomMap;
00920 }
00921 
00922 #endif // __STORE_HORIZONTAL_
00923 
00924 QMap<QString, QString>  OContactAccessBackend_SQL::requestCustom( int uid ) const
00925 {
00926         QTime t;
00927         t.start();
00928 
00929         QMap<QString, QString> customMap;
00930         
00931         FindCustomQuery query( uid );
00932         OSQLResult res_custom = m_driver->query( &query );
00933 
00934         if ( res_custom.state() == OSQLResult::Failure ) {
00935                 qWarning("OSQLResult::Failure in find query !!");
00936                 QMap<QString, QString> empty;
00937                 return empty;
00938         }
00939 
00940         OSQLResultItem::ValueList list = res_custom.results();
00941         OSQLResultItem::ValueList::Iterator it = list.begin();
00942         for ( ; it != list.end(); ++it ) {
00943                 customMap.insert( (*it).data( "type" ), (*it).data( "value" ) );
00944         }
00945 
00946         qWarning("RequestCustom needed: %d ms", t.elapsed() );
00947         return customMap;
00948 }

Generated on Sat Nov 5 16:16:14 2005 for OPIE by  doxygen 1.4.2