libopie PIM API Documentation

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