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                              This file is part of the Opie Project
00003                              Copyright (C) Stefan Eilers <eilers.stefan@epost.de>
00004               =.             Copyright (C) The Opie Team <opie-devel@handhelds.org>
00005             .=l.
00006            .>+-=
00007  _;:,     .>    :=|.         This program is free software; you can
00008 .> <`_,   >  .   <=          redistribute it and/or  modify it under
00009 :`=1 )Y*s>-.--   :           the terms of the GNU Library General Public
00010 .="- .-=="i,     .._         License as published by the Free Software
00011  - .   .-<_>     .<>         Foundation; either version 2 of the License,
00012      ._= =}       :          or (at your option) any later version.
00013     .%`+i>       _;_.
00014     .i_,=:_.      -<s.       This program is distributed in the hope that
00015      +  .  -:.       =       it will be useful,  but WITHOUT ANY WARRANTY;
00016     : ..    .:,     . . .    without even the implied warranty of
00017     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00018   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU
00019 ..}^=.=       =       ;      Library General Public License for more
00020 ++=   -.     .`     .:       details.
00021  :     =  ...= . :.=-
00022  -.   .:....=;==+<;          You should have received a copy of the GNU
00023   -_. . .   )=.  =           Library General Public License along with
00024     --        :-=`           this library; see the file COPYING.LIB.
00025                              If not, write to the Free Software Foundation,
00026                              Inc., 59 Temple Place - Suite 330,
00027                              Boston, MA 02111-1307, USA.
00028 */
00029 /*
00030  * SQL Backend for the OPIE-Contact Database.
00031  */
00032 
00033 #include "ocontactaccessbackend_sql.h"
00034 
00035 /* OPIE */
00036 #include <opie2/opimcontact.h>
00037 #include <opie2/opimcontactfields.h>
00038 #include <opie2/opimdateconversion.h>
00039 #include <opie2/osqldriver.h>
00040 #include <opie2/osqlresult.h>
00041 #include <opie2/osqlmanager.h>
00042 #include <opie2/osqlquery.h>
00043 #include <opie2/odebug.h>
00044 
00045 #include <qpe/global.h>
00046 #include <qpe/recordfields.h>
00047 
00048 /* QT */
00049 #include <qarray.h>
00050 #include <qdatetime.h>
00051 #include <qstringlist.h>
00052 
00053 
00054 using namespace Opie;
00055 using namespace Opie::DB;
00056 
00057 
00058 /*
00059  * Implementation of used query types * CREATE query
00060  * LOAD query
00061  * INSERT
00062  * REMOVE
00063  * CLEAR
00064  */
00065 namespace {
00069     class CreateQuery : public OSQLQuery {
00070     public:
00071         CreateQuery();
00072         ~CreateQuery();
00073         QString query()const;
00074     };
00075 
00079     class ClearQuery : public OSQLQuery {
00080     public:
00081         ClearQuery();
00082         ~ClearQuery();
00083         QString query()const;
00084 
00085     };
00086 
00087 
00092     class LoadQuery : public OSQLQuery {
00093     public:
00094         LoadQuery();
00095         ~LoadQuery();
00096         QString query()const;
00097     };
00098 
00102     class InsertQuery : public OSQLQuery {
00103     public:
00104         InsertQuery(const OPimContact& );
00105         ~InsertQuery();
00106         QString query()const;
00107     private:
00108         OPimContact m_contact;
00109     };
00110 
00111 
00115     class RemoveQuery : public OSQLQuery {
00116     public:
00117         RemoveQuery(int uid );
00118         ~RemoveQuery();
00119         QString query()const;
00120     private:
00121         int m_uid;
00122     };
00123 
00127     class FindQuery : public OSQLQuery {
00128     public:
00129         FindQuery(int uid);
00130         FindQuery(const UIDArray& );
00131         ~FindQuery();
00132         QString query()const;
00133     private:
00134         QString single()const;
00135         QString multi()const;
00136         UIDArray m_uids;
00137         int m_uid;
00138     };
00139 
00143     class FindCustomQuery : public OSQLQuery {
00144     public:
00145         FindCustomQuery(int uid);
00146         FindCustomQuery(const UIDArray& );
00147         ~FindCustomQuery();
00148         QString query()const;
00149     private:
00150         QString single()const;
00151         QString multi()const;
00152         UIDArray m_uids;
00153         int m_uid;
00154     };
00155 
00156 
00157 
00158     // We using two tables to store the information:
00159     // 1. addressbook  : It contains General information about the contact (non custom)
00160     // 2. custom_data  : Not official supported entries
00161     // All tables are connected by the uid of the contact.
00162     // Maybe I should add a table for meta-information ?
00163     CreateQuery::CreateQuery() : OSQLQuery() {}
00164     CreateQuery::~CreateQuery() {}
00165     QString CreateQuery::query()const {
00166         QString qu;
00167 
00168         qu += "create table addressbook( uid PRIMARY KEY ";
00169 
00170         QStringList fieldList = OPimContactFields::untrfields( false );
00171         for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
00172             qu += QString( ",\"%1\" VARCHAR(10)" ).arg( *it );
00173         }
00174         qu += " );";
00175 
00176         qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR(10), priority INTEGER, value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );";
00177 
00178         return qu;
00179     }
00180 
00181     ClearQuery::ClearQuery()
00182         : OSQLQuery() {}
00183     ClearQuery::~ClearQuery() {}
00184     QString ClearQuery::query()const {
00185         QString qu = "drop table addressbook;";
00186         qu += "drop table custom_data;";
00187 //      qu += "drop table dates;";
00188         return qu;
00189     }
00190 
00191 
00192     LoadQuery::LoadQuery() : OSQLQuery() {}
00193     LoadQuery::~LoadQuery() {}
00194     QString LoadQuery::query()const {
00195         QString qu;
00196         qu += "select uid from addressbook";
00197 
00198         return qu;
00199     }
00200 
00201 
00202     InsertQuery::InsertQuery( const OPimContact& contact )
00203         : OSQLQuery(), m_contact( contact ) {
00204     }
00205 
00206     InsertQuery::~InsertQuery() {
00207     }
00208 
00209     /*
00210      * converts from a OPimContact to a query
00211      */
00212     QString InsertQuery::query()const{
00213 
00214         QString qu;
00215         qu  += "insert into addressbook VALUES( " +
00216             QString::number( m_contact.uid() );
00217 
00218         // Get all information out of the contact-class
00219         // Remember: The category is stored in contactMap, too !
00220         QMap<int, QString> contactMap = m_contact.toMap();
00221 
00222         QStringList fieldList = OPimContactFields::untrfields( false );
00223         QMap<QString, int> translate = OPimContactFields::untrFieldsToId();
00224         for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
00225             // Convert Column-String to Id and get value for this id..
00226             // Hmmm.. Maybe not very cute solution..
00227             int id = translate[*it];
00228             switch ( id ){
00229             case Qtopia::Birthday:
00230             case Qtopia::Anniversary:{
00231                 QDate day;
00232                 if ( id == Qtopia::Birthday ){
00233                     day = m_contact.birthday();
00234                 } else {
00235                     day = m_contact.anniversary();
00236                 }
00237                 // These entries should stored in a special format
00238                 // year-month-day
00239                 if ( day.isValid() ){
00240                     qu += QString(",\"%1-%2-%3\"")
00241                         .arg( QString::number( day.year() ).rightJustify( 4, '0' ) )
00242                         .arg( QString::number( day.month() ).rightJustify( 2, '0' ) )
00243                         .arg( QString::number( day.day() ).rightJustify( 2, '0' ) );
00244                 } else {
00245                     qu += ",\"\"";
00246                 }
00247             }
00248                 break;
00249             default:
00250                 qu += QString( ",\"%1\"" ).arg( contactMap[id] );
00251             }
00252         }
00253         qu += " );";
00254 
00255 
00256         // Now add custom data..
00257         int id = 0;
00258         id = 0;
00259         QMap<QString, QString> customMap = m_contact.toExtraMap();
00260         for( QMap<QString, QString>::Iterator it = customMap.begin();
00261              it != customMap.end(); ++it ){
00262             qu  += "insert into custom_data VALUES("
00263                 +  QString::number( m_contact.uid() )
00264                 + ","
00265                 +  QString::number( id++ )
00266                 + ",'"
00267                 + it.key()
00268                 + "',"
00269                 + "0" // Priority for future enhancements
00270                 + ",'"
00271                 + it.data()
00272                 + "');";
00273         }
00274         // qu  += "commit;";
00275         odebug << "add " << qu << "" << oendl;
00276         return qu;
00277     }
00278 
00279 
00280     RemoveQuery::RemoveQuery(int uid )
00281         : OSQLQuery(), m_uid( uid ) {}
00282 
00283     RemoveQuery::~RemoveQuery() {}
00284 
00285     QString RemoveQuery::query()const {
00286         QString qu = "DELETE from addressbook where uid = "
00287             + QString::number(m_uid) + ";";
00288         qu += "DELETE from custom_data where uid = "
00289             + QString::number(m_uid) + ";";
00290         return qu;
00291     }
00292 
00293 
00294     FindQuery::FindQuery(int uid)
00295         : OSQLQuery(), m_uid( uid ) {
00296     }
00297     FindQuery::FindQuery(const UIDArray& ints)
00298         : OSQLQuery(), m_uids( ints ){
00299     }
00300     FindQuery::~FindQuery() {
00301     }
00302     QString FindQuery::query()const{
00303            if ( m_uids.count() == 0 )
00304                    return single();
00305            else
00306                    return multi();
00307     }
00308 
00309 
00310 
00311     QString FindQuery::multi()const {
00312             QString qu = "select * from addressbook where";
00313             for (uint i = 0; i < m_uids.count(); i++ ) {
00314                     qu += " uid = " + QString::number( m_uids[i] ) + " OR";
00315             }
00316             qu.remove( qu.length()-2, 2 ); // Hmmmm..
00317 
00318             odebug << "find query: " << qu << "" << oendl;
00319             return qu;
00320     }
00321 
00322     QString FindQuery::single()const{
00323             QString qu = "select *";
00324             qu += " from addressbook where uid = " + QString::number(m_uid);
00325 
00326             // owarn << "find query: " << qu << "" << oendl;
00327             return qu;
00328     }
00329 
00330 
00331     FindCustomQuery::FindCustomQuery(int uid)
00332         : OSQLQuery(), m_uid( uid ) {
00333     }
00334     FindCustomQuery::FindCustomQuery(const UIDArray& ints)
00335         : OSQLQuery(), m_uids( ints ){
00336     }
00337     FindCustomQuery::~FindCustomQuery() {
00338     }
00339     QString FindCustomQuery::query()const{
00340 //      if ( m_uids.count() == 0 )
00341             return single();
00342     }
00343     QString FindCustomQuery::single()const{
00344         QString qu = "select uid, type, value from custom_data where uid = ";
00345         qu += QString::number(m_uid);
00346         return qu;
00347     }
00348 
00349 };
00350 
00351 
00352 /* --------------------------------------------------------------------------- */
00353 
00354 namespace Opie {
00355 
00356 OPimContactAccessBackend_SQL::OPimContactAccessBackend_SQL ( const QString& /* appname */,
00357                                const QString& filename ):
00358     OPimContactAccessBackend(), m_changed(false), m_driver( NULL )
00359 {
00360     odebug << "C'tor OPimContactAccessBackend_SQL starts" << oendl;
00361     QTime t;
00362     t.start();
00363 
00364     /* Expecting to access the default filename if nothing else is set */
00365     if ( filename.isEmpty() ){
00366         m_fileName = Global::applicationFileName( "addressbook","addressbook.db" );
00367     } else
00368         m_fileName = filename;
00369 
00370     // Get the standart sql-driver from the OSQLManager..
00371     OSQLManager man;
00372     m_driver = man.standard();
00373     m_driver->setUrl( m_fileName );
00374 
00375     load();
00376 
00377     odebug << "C'tor OPimContactAccessBackend_SQL ends: " << t.elapsed() << " ms" << oendl;
00378 }
00379 
00380 OPimContactAccessBackend_SQL::~OPimContactAccessBackend_SQL ()
00381 {
00382     if( m_driver )
00383         delete m_driver;
00384 }
00385 
00386 bool OPimContactAccessBackend_SQL::load ()
00387 {
00388     if (!m_driver->open() )
00389         return false;
00390 
00391     // Don't expect that the database exists.
00392     // It is save here to create the table, even if it
00393     // do exist. ( Is that correct for all databases ?? )
00394     CreateQuery creat;
00395     OSQLResult res = m_driver->query( &creat );
00396 
00397     update();
00398 
00399     return true;
00400 
00401 }
00402 
00403 bool OPimContactAccessBackend_SQL::reload()
00404 {
00405     return load();
00406 }
00407 
00408 bool OPimContactAccessBackend_SQL::save()
00409 {
00410     return m_driver->close();  // Shouldn't m_driver->sync be better than close ? (eilers)
00411 }
00412 
00413 
00414 void OPimContactAccessBackend_SQL::clear ()
00415 {
00416     ClearQuery cle;
00417     OSQLResult res = m_driver->query( &cle );
00418 
00419     reload();
00420 }
00421 
00422 bool OPimContactAccessBackend_SQL::wasChangedExternally()
00423 {
00424     return false;
00425 }
00426 
00427 UIDArray OPimContactAccessBackend_SQL::allRecords() const
00428 {
00429 
00430     // FIXME: Think about cute handling of changed tables..
00431     // Thus, we don't have to call update here...
00432     if ( m_changed )
00433         ((OPimContactAccessBackend_SQL*)this)->update();
00434 
00435     return m_uids;
00436 }
00437 
00438 bool OPimContactAccessBackend_SQL::add ( const OPimContact &newcontact )
00439 {
00440     odebug << "add in contact SQL-Backend" << oendl;
00441     InsertQuery ins( newcontact );
00442     OSQLResult res = m_driver->query( &ins );
00443 
00444     if ( res.state() == OSQLResult::Failure )
00445         return false;
00446 
00447     int c = m_uids.count();
00448     m_uids.resize( c+1 );
00449     m_uids[c] = newcontact.uid();
00450 
00451     return true;
00452 }
00453 
00454 
00455 bool OPimContactAccessBackend_SQL::remove ( int uid )
00456 {
00457     RemoveQuery rem( uid );
00458     OSQLResult res = m_driver->query(&rem );
00459 
00460     if ( res.state() == OSQLResult::Failure )
00461         return false;
00462 
00463     m_changed = true;
00464 
00465     return true;
00466 }
00467 
00468 bool OPimContactAccessBackend_SQL::replace ( const OPimContact &contact )
00469 {
00470     if ( !remove( contact.uid() ) )
00471         return false;
00472 
00473     return add( contact );
00474 }
00475 
00476 
00477 OPimContact OPimContactAccessBackend_SQL::find ( int uid ) const
00478 {
00479     odebug << "OPimContactAccessBackend_SQL::find(" << uid << ")" << oendl;
00480     QTime t;
00481     t.start();
00482 
00483     OPimContact retContact( requestNonCustom( uid ) );
00484     retContact.setExtraMap( requestCustom( uid ) );
00485 
00486     odebug << "OPimContactAccessBackend_SQL::find() needed: " << t.elapsed() << " ms" << oendl;
00487     return retContact;
00488 }
00489 
00490 OPimContact OPimContactAccessBackend_SQL::find( int uid, const UIDArray& queryUids, uint current, Frontend::CacheDirection direction ) const
00491 {
00492     odebug << "OPimContactAccessBackend_SQL::find( ..multi.. )" << oendl;
00493     odebug << "searching for " << uid << "" << oendl;
00494 
00495     QTime t;
00496     t.start();
00497 
00498     uint numReadAhead = readAhead();
00499     QArray<int> searchList( numReadAhead );
00500 
00501     uint size =0;
00502 
00503     // Build an array with all elements which should be requested and cached
00504     // We will just request "numReadAhead" elements, starting from "current" position in
00505     // the list of many uids !
00506     switch( direction ) {
00507         /* forward */
00508     case Frontend::Forward:
00509         for ( uint i = current; i < queryUids.count() && size < numReadAhead; i++ ) {
00510             searchList[size] = queryUids[i];
00511             size++;
00512         }
00513         break;
00514         /* reverse */
00515     case Frontend::Reverse:
00516         for ( uint i = current; i != 0 && size <  numReadAhead; i-- ) {
00517             searchList[size] = queryUids[i];
00518             size++;
00519         }
00520         break;
00521     }
00522 
00523     //Shrink to real size..
00524     searchList.resize( size );
00525 
00526     OPimContact retContact( requestContactsAndCache( uid, searchList ) );
00527 
00528     odebug << "OPimContactAccessBackend_SQL::find( ..multi.. ) needed: " << t.elapsed() << " ms" << oendl;
00529     return retContact;
00530 }
00531 
00532 
00533 UIDArray OPimContactAccessBackend_SQL::queryByExample ( const UIDArray& uidlist, const OPimContact &query, int settings, 
00534                                                            const QDateTime& qd ) const
00535 {
00536     QString searchQuery = "";
00537     QString datediff_query = "";
00538     QString uid_query = "";
00539 
00540     // Just add uid's selection if we really try to search in a subset of all uids! Otherwise this would
00541     // just take time and memory!
00542     if ( uidlist.count() != m_uids.count() ) {
00543             uid_query += " (";
00544 
00545             for ( uint i = 0; i < uidlist.count(); i++ ) {
00546                     uid_query += " uid = " + QString::number( uidlist[i] ) + " OR";
00547             }
00548             uid_query.remove( uid_query.length()-2, 2 ); // Hmmmm..
00549             uid_query += " ) AND ";
00550     }
00551 
00552 
00553     QDate startDate;
00554 
00555     if ( qd.isValid() )
00556         startDate = qd.date();
00557     else
00558         startDate = QDate::currentDate();
00559 
00560 
00561     QMap<int, QString> queryFields = query.toMap();
00562     QStringList fieldList = OPimContactFields::untrfields( false );
00563     QMap<QString, int> translate = OPimContactFields::untrFieldsToId();
00564 
00565     // Convert every filled field to a SQL-Query
00566 //  bool isAnyFieldSelected = false;
00567     for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
00568 
00569         int id = translate[*it];
00570         QString queryStr = queryFields[id];
00571         QDate* endDate = 0l;
00572 
00573         if ( !queryStr.isEmpty() ){
00574             // If something is alredy stored in the query, add an "AND"
00575             // to the end of the string to prepare for the next ..
00576             if ( !searchQuery.isEmpty() )
00577                 searchQuery += " AND";
00578 
00579 //          isAnyFieldSelected = true;
00580             switch( id ){
00581             case Qtopia::Birthday:
00582                 endDate = new QDate( query.birthday() );
00583                 // Fall through !
00584             case Qtopia::Anniversary:
00585                 if ( endDate == 0l )
00586                     endDate = new QDate( query.anniversary() );
00587 
00588                 if ( settings & OPimContactAccess::DateDiff ) {
00589                     // To handle datediffs correctly, we need to remove the year information from
00590                     // the birthday and anniversary. 
00591                     // To do this efficiently, we will create a temporary table which contains the
00592                     // information we need and do the query on it. 
00593                     // This table is just visible for this process and will be removed
00594                     // automatically after using.
00595                                 datediff_query = "SELECT uid,substr(\"Birthday\", 6, 10) as \"BirthdayMD\", substr(\"Anniversary\", 6, 10) as \"AnniversaryMD\" FROM addressbook WHERE ( \"Birthday\" != '' OR \"Anniversary\" != '' ) AND ";
00596                                 datediff_query += QString( " (\"%1MD\" <= '%2-%3\' AND \"%4MD\" >= '%5-%6')" )
00597                         .arg( *it )
00598                             //.arg( QString::number( endDate->year() ).rightJustify( 4, '0' ) )
00599                         .arg( QString::number( endDate->month() ).rightJustify( 2, '0' ) )
00600                         .arg( QString::number( endDate->day() ).rightJustify( 2, '0' ) )
00601                         .arg( *it )
00602                             //.arg( QString::number( startDate.year() ).rightJustify( 4, '0' ) )
00603                         .arg( QString::number( startDate.month() ).rightJustify( 2, '0' ) )
00604                         .arg( QString::number( startDate.day() ).rightJustify( 2, '0' ) ) ;
00605                 }
00606 
00607                 if ( settings & OPimContactAccess::DateYear ){
00608                     searchQuery += QString( " (\"%1\" LIKE '%2-%')" )
00609                         .arg( *it )
00610                         .arg( QString::number( endDate->year() ).rightJustify( 4, '0' ) );
00611                 }
00612 
00613                 if ( settings & OPimContactAccess::DateMonth ){
00614                     if ( settings & OPimContactAccess::DateYear )
00615                         searchQuery += " AND";
00616 
00617                     searchQuery += QString( " (\"%1\" LIKE '%-%2-%')" )
00618                         .arg( *it )
00619                         .arg( QString::number( endDate->month() ).rightJustify( 2, '0' ) );
00620                 }
00621 
00622                 if ( settings & OPimContactAccess::DateDay ){
00623                     if ( ( settings & OPimContactAccess::DateYear )
00624                          || ( settings & OPimContactAccess::DateMonth ) )
00625                         searchQuery += " AND";
00626 
00627                     searchQuery += QString( " (\"%1\" LIKE '%-%-%2')" )
00628                         .arg( *it )
00629                         .arg( QString::number( endDate->day() ).rightJustify( 2, '0' ) );
00630                 }
00631 
00632                 break;
00633             default:
00634                 // Switching between case sensitive and insensitive...
00635                 // LIKE is not case sensitive, GLOB is case sensitive
00636                 // Do exist a better solution to switch this ?
00637                 if ( settings & OPimContactAccess::IgnoreCase )
00638                     searchQuery += " (\"" + *it + "\"" + " LIKE " + "'"
00639                         + queryStr.replace(QRegExp("\\*"),"%") + "'" + ")";
00640                 else
00641                     searchQuery += " (\"" + *it + "\"" + " GLOB " + "'"
00642                         + queryStr + "'" + ")";
00643 
00644             }
00645         }
00646 
00647         delete endDate;
00648 
00649         // The following if line is a replacement for 
00650         // if ( searchQuery.endsWith( "AND" ) )
00651         if ( searchQuery.findRev( "AND" ) == static_cast<int>( searchQuery.length() - 3 ) ){
00652                 odebug << "remove AND" << oendl;
00653                 searchQuery.remove( searchQuery.length()-3, 3 ); // Hmmmm..
00654         }
00655 
00656     }
00657 
00658     // Now compose the complete query
00659     QString qu = "SELECT uid FROM addressbook WHERE " + uid_query; 
00660 
00661     if ( !datediff_query.isEmpty() && !searchQuery.isEmpty() ){
00662             // If we use DateDiff, we have to intersect two queries.
00663             qu = datediff_query + QString( " INTERSECT " ) + qu + searchQuery;
00664     } else if ( datediff_query.isEmpty() && !searchQuery.isEmpty() ){
00665             qu += searchQuery;
00666     } else if ( !datediff_query.isEmpty() && searchQuery.isEmpty() ){
00667             qu = datediff_query;
00668     } else if ( datediff_query.isEmpty() && searchQuery.isEmpty() ){
00669             UIDArray empty;
00670             return empty;
00671     } 
00672 
00673     odebug << "queryByExample query: " << qu << "" << oendl;
00674 
00675     // Execute query and return the received uid's
00676     OSQLRawQuery raw( qu );
00677     OSQLResult res = m_driver->query( &raw );
00678     if ( res.state() != OSQLResult::Success ){
00679         UIDArray empty;
00680         return empty;
00681     }
00682 
00683     UIDArray list = extractUids( res );
00684 
00685     return list;
00686 }
00687 
00688 UIDArray OPimContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const
00689 {
00690 #if 0
00691     QArray<int> nix(0);
00692     return nix;
00693 
00694 #else
00695     QString qu = "SELECT uid FROM addressbook WHERE (";
00696     QString searchlist;
00697 
00698     QStringList fieldList = OPimContactFields::untrfields( false );
00699     // QMap<QString, int> translate = OPimContactFields::untrFieldsToId();
00700     for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
00701         if ( !searchlist.isEmpty() )
00702             searchlist += " OR ";
00703         searchlist += " rlike(\""+ r.pattern() + "\",\"" + *it + "\") ";
00704     }
00705 
00706     qu = qu + searchlist + ")";
00707 
00708     odebug << "query: " << qu << "" << oendl;
00709 
00710     OSQLRawQuery raw( qu );
00711     OSQLResult res = m_driver->query( &raw );
00712 
00713     return extractUids( res );
00714 
00715 
00716 #endif
00717 }
00718 
00719 const uint OPimContactAccessBackend_SQL::querySettings() const
00720 {
00721     return OPimContactAccess::IgnoreCase
00722         | OPimContactAccess::WildCards
00723         | OPimContactAccess::DateDiff
00724         | OPimContactAccess::DateYear
00725         | OPimContactAccess::DateMonth
00726         | OPimContactAccess::DateDay
00727         ;
00728 }
00729 
00730 bool OPimContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const
00731 {
00732     /* OPimContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
00733      * may be added with any of the other settings. IgnoreCase should never used alone.
00734      * Wildcards, RegExp, ExactMatch should never used at the same time...
00735      */
00736 
00737     // Step 1: Check whether the given settings are supported by this backend
00738     if ( ( querySettings & (
00739                 OPimContactAccess::IgnoreCase
00740                 | OPimContactAccess::WildCards
00741                 | OPimContactAccess::DateDiff
00742                 | OPimContactAccess::DateYear
00743                 | OPimContactAccess::DateMonth
00744                 | OPimContactAccess::DateDay
00745 //              | OPimContactAccess::RegExp
00746 //              | OPimContactAccess::ExactMatch
00747                    ) ) != querySettings )
00748         return false;
00749 
00750     // Step 2: Check whether the given combinations are ok..
00751 
00752     // IngoreCase alone is invalid
00753     if ( querySettings == OPimContactAccess::IgnoreCase )
00754         return false;
00755 
00756     // WildCards, RegExp and ExactMatch should never used at the same time
00757     switch ( querySettings & ~( OPimContactAccess::IgnoreCase
00758                     | OPimContactAccess::DateDiff
00759                     | OPimContactAccess::DateYear
00760                     | OPimContactAccess::DateMonth
00761                     | OPimContactAccess::DateDay
00762                     )
00763          ){
00764     case OPimContactAccess::RegExp:
00765         return ( true );
00766     case OPimContactAccess::WildCards:
00767         return ( true );
00768     case OPimContactAccess::ExactMatch:
00769         return ( true );
00770     case 0: // one of the upper removed bits were set..
00771         return ( true );
00772     default:
00773         return ( false );
00774     }
00775 
00776 }
00777 
00778 UIDArray OPimContactAccessBackend_SQL::sorted( const UIDArray& ar, bool asc, int sortOrder,
00779                                   int filter, const QArray<int>& categories )const 
00780 {
00781     QTime t;
00782     t.start();
00783 
00784     QString query = "SELECT uid FROM addressbook";
00785 
00786     query += " WHERE (";
00787     for ( uint i = 0; i < ar.count(); i++ ) {
00788             query += " uid = " + QString::number( ar[i] ) + " OR";
00789     }
00790     query.remove( query.length()-2, 2 ); // Hmmmm..
00791     query += ")";
00792 
00793 
00794     if ( filter != OPimBase::FilterOff ){
00795             if ( filter & OPimContactAccess::DoNotShowWithCategory ){
00796                     query += " AND ( \"Categories\" == '' )";
00797             } else if ( filter & OPimBase::FilterCategory ){
00798                     query += " AND (";
00799                     for ( uint i = 0; i < categories.count(); i++ ){
00800                             query += "\"Categories\" LIKE";
00801                             query += QString( " '%" ) + QString::number( categories[i] ) + "%' OR";
00802                     }
00803                     query.remove( query.length()-2, 2 ); // Hmmmm..
00804                     query += ")";
00805             }
00806 
00807             if ( filter & OPimContactAccess::DoNotShowWithoutChildren ){
00808                     query += " AND ( \"Children\" != '' )";
00809             }
00810 
00811             if ( filter & OPimContactAccess::DoNotShowWithoutAnniversary ){
00812                     query += " AND ( \"Anniversary\" != '' )";
00813             }
00814 
00815             if ( filter & OPimContactAccess::DoNotShowWithoutBirthday ){
00816                     query += " AND ( \"Birthday\" != '' )";
00817             }
00818 
00819             if ( filter & OPimContactAccess::DoNotShowWithoutHomeAddress ){
00820                     // Expect that no Street means no Address, too! (eilers)
00821                     query += " AND ( \"Home Street\" != '' )";
00822             }
00823 
00824             if ( filter & OPimContactAccess::DoNotShowWithoutBusinessAddress ){
00825                     // Expect that no Street means no Address, too! (eilers)
00826                     query += " AND ( \"Business Street\" != '' )";
00827             } 
00828 
00829     }
00830    
00831     query += " ORDER BY";
00832     
00833     switch ( sortOrder ) {
00834     case OPimContactAccess::SortSummary:
00835             query += " \"Notes\"";
00836             break;
00837     case OPimContactAccess::SortByCategory:
00838             query += " \"Categories\"";
00839             break;
00840     case OPimContactAccess::SortByDate:
00841             query += " \"\"";
00842             break;
00843     case OPimContactAccess::SortTitle:
00844             query += " \"Name Title\"";
00845             break;
00846     case OPimContactAccess::SortFirstName:
00847             query += " \"First Name\"";
00848             break;
00849     case OPimContactAccess::SortMiddleName:
00850             query += " \"Middle Name\"";
00851             break;
00852     case OPimContactAccess::SortLastName:
00853             query += " \"Last Name\"";
00854             break;
00855    case OPimContactAccess::SortFileAsName:
00856             query += " \"File As\"";
00857             break;
00858     case OPimContactAccess::SortSuffix:
00859             query += " \"Suffix\"";
00860             break;
00861     case OPimContactAccess::SortEmail:
00862             query += " \"Default Email\"";
00863             break;
00864     case OPimContactAccess::SortNickname:
00865             query += " \"Nickname\"";
00866             break;
00867     case OPimContactAccess::SortAnniversary:
00868             query += " \"Anniversary\"";
00869             break;
00870     case OPimContactAccess::SortBirthday:
00871             query += " \"Birthday\"";
00872             break;
00873     case OPimContactAccess::SortGender:
00874             query += " \"Gender\"";
00875             break;
00876     case OPimContactAccess::SortBirthdayWithoutYear:
00877             query += " substr(\"Birthday\", 6, 10)";
00878             break;
00879     case OPimContactAccess::SortAnniversaryWithoutYear:
00880             query += " substr(\"Anniversary\", 6, 10)";
00881             break;
00882     default:
00883            query += " \"Last Name\"";
00884     }
00885 
00886     if ( !asc )
00887         query += " DESC";
00888 
00889 
00890     odebug << "sorted query is: " << query << "" << oendl;
00891 
00892     OSQLRawQuery raw( query );
00893     OSQLResult res = m_driver->query( &raw );
00894     if ( res.state() != OSQLResult::Success ){
00895         UIDArray empty;
00896         return empty;
00897     }
00898 
00899     UIDArray list = extractUids( res );
00900 
00901     odebug << "sorted needed " << t.elapsed() << " ms!" << oendl;
00902     return list;
00903 }
00904 
00905 
00906 void OPimContactAccessBackend_SQL::update()
00907 {
00908     odebug << "Update starts" << oendl;
00909     QTime t;
00910     t.start();
00911 
00912     // Now load the database set and extract the uid's
00913     // which will be held locally
00914 
00915     LoadQuery lo;
00916     OSQLResult res = m_driver->query(&lo);
00917     if ( res.state() != OSQLResult::Success )
00918         return;
00919 
00920     m_uids = extractUids( res );
00921 
00922     m_changed = false;
00923 
00924     odebug << "Update ends " << t.elapsed() << " ms" << oendl;
00925 }
00926 
00927 UIDArray OPimContactAccessBackend_SQL::extractUids( OSQLResult& res ) const
00928 {
00929     odebug << "extractUids" << oendl;
00930     QTime t;
00931     t.start();
00932     OSQLResultItem::ValueList list = res.results();
00933     OSQLResultItem::ValueList::Iterator it;
00934     UIDArray ints(list.count() );
00935     odebug << " count = " << list.count() << "" << oendl;
00936 
00937     int i = 0;
00938     for (it = list.begin(); it != list.end(); ++it ) {
00939         ints[i] =  (*it).data("uid").toInt();
00940         i++;
00941     }
00942     odebug << "extractUids ready: count2 = " << i << " needs " << t.elapsed() << " ms" << oendl;
00943 
00944     return ints;
00945 
00946 }
00947 
00948 QMap<int, QString>  OPimContactAccessBackend_SQL::requestNonCustom( int uid ) const
00949 {
00950     QTime t;
00951     t.start();
00952 
00953     int t2needed = 0;
00954     int t3needed = 0;
00955     QTime t2;
00956     t2.start();
00957     FindQuery query( uid );
00958     OSQLResult res_noncustom = m_driver->query( &query );
00959     t2needed = t2.elapsed();
00960 
00961     OSQLResultItem resItem = res_noncustom.first();
00962 
00963     QMap<int, QString> nonCustomMap;
00964     QTime t3;
00965     t3.start();
00966     nonCustomMap = fillNonCustomMap( resItem );
00967     t3needed = t3.elapsed();
00968 
00969 
00970     // odebug << "Adding UID: " << resItem.data( "uid" ) << "" << oendl;
00971     odebug << "RequestNonCustom needed: insg.:" << t.elapsed() << " ms, query: " << t2needed
00972            << " ms, mapping: " << t3needed << " ms" << oendl;
00973 
00974     return nonCustomMap;
00975 }
00976 
00977 /* Returns contact requested by uid and fills cache with contacts requested by uids in the cachelist */
00978 OPimContact OPimContactAccessBackend_SQL::requestContactsAndCache( int uid, const UIDArray& uidlist )const
00979 {
00980         // We want to get all contacts with one query.
00981         // We don't have to add the given uid to the uidlist, it is expected to be there already (see opimrecordlist.h).
00982         // All contacts will be stored in the cache, afterwards the contact with the user id "uid" will be returned
00983         // by using the cache..
00984         UIDArray cachelist = uidlist;
00985         OPimContact retContact;
00986 
00987         odebug << "Reqest and cache" << cachelist.size() << "elements !" << oendl;
00988 
00989         QTime t;
00990         t.start();
00991 
00992         int t2needed = 0;
00993         int t3needed = 0;
00994         QTime t2;
00995         t2.start();
00996         FindQuery query( cachelist );
00997         OSQLResult res_noncustom = m_driver->query( &query );
00998         t2needed = t2.elapsed();
00999 
01000         QMap<int, QString> nonCustomMap;
01001         QTime t3;
01002         t3.start();
01003         OSQLResultItem resItem = res_noncustom.first();
01004         do {
01005                 OPimContact contact( fillNonCustomMap( resItem ) );
01006                 contact.setExtraMap( requestCustom( contact.uid() ) );
01007                 odebug << "Caching uid: " << contact.uid() << oendl;
01008                 cache( contact );
01009                 if ( contact.uid() == uid )
01010                         retContact = contact;
01011                 resItem = res_noncustom.next();
01012         } while ( ! res_noncustom.atEnd() ); //atEnd() is true if we are past(!) the list !!
01013         t3needed = t3.elapsed();
01014 
01015 
01016         // odebug << "Adding UID: " << resItem.data( "uid" ) << "" << oendl;
01017         odebug << "RequestContactsAndCache needed: insg.:" << t.elapsed() << " ms, query: " << t2needed
01018                << " ms, mapping: " << t3needed << " ms" << oendl;
01019 
01020         return retContact;
01021 }
01022 
01023 QMap<int, QString> OPimContactAccessBackend_SQL::fillNonCustomMap( const OSQLResultItem& resultItem ) const
01024 {
01025     QMap<int, QString> nonCustomMap;
01026 
01027     // Now loop through all columns
01028     QStringList fieldList = OPimContactFields::untrfields( false );
01029     QMap<QString, int> translate = OPimContactFields::untrFieldsToId();
01030     for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
01031         // Get data for the selected column and store it with the
01032         // corresponding id into the map..
01033 
01034         int id =  translate[*it];
01035         QString value = resultItem.data( (*it) );
01036 
01037         // odebug << "Reading " << (*it) << "... found: " << value << "" << oendl;
01038 
01039         switch( id ){
01040         case Qtopia::Birthday:
01041         case Qtopia::Anniversary:{
01042             // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
01043             QStringList list = QStringList::split( '-', value );
01044             QStringList::Iterator lit = list.begin();
01045             int year  = (*lit).toInt();
01046             int month = (*(++lit)).toInt();
01047             int day   = (*(++lit)).toInt();
01048             if ( ( day != 0 ) && ( month != 0 ) && ( year != 0 ) ){
01049                  QDate date( year, month, day );
01050                  nonCustomMap.insert( id, OPimDateConversion::dateToString( date ) );
01051             }
01052         }
01053             break;
01054         case Qtopia::AddressCategory:
01055             odebug << "Category is: " << value << "" << oendl;
01056         default:
01057             nonCustomMap.insert( id, value );
01058         }
01059     }
01060 
01061     nonCustomMap.insert( Qtopia::AddressUid, resultItem.data( "uid" ) );
01062 
01063     return nonCustomMap;
01064 }
01065 
01066 
01067 QMap<QString, QString>  OPimContactAccessBackend_SQL::requestCustom( int uid ) const
01068 {
01069     QTime t;
01070     t.start();
01071 
01072     QMap<QString, QString> customMap;
01073 
01074     FindCustomQuery query( uid );
01075     OSQLResult res_custom = m_driver->query( &query );
01076 
01077     if ( res_custom.state() == OSQLResult::Failure ) {
01078         owarn << "OSQLResult::Failure in find query !!" << oendl;
01079         QMap<QString, QString> empty;
01080         return empty;
01081     }
01082 
01083     OSQLResultItem::ValueList list = res_custom.results();
01084     OSQLResultItem::ValueList::Iterator it = list.begin();
01085     for ( ; it != list.end(); ++it ) {
01086         customMap.insert( (*it).data( "type" ), (*it).data( "value" ) );
01087     }
01088 
01089     odebug << "RequestCustom needed: " << t.elapsed() << " ms" << oendl;
01090     return customMap;
01091 }
01092 
01093 }

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