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

odatebookaccessbackend_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-Calender Database.
00031  *
00032  */
00033 
00034 /* OPIE */
00035 #include <opie2/osqldriver.h>
00036 #include <opie2/osqlmanager.h>
00037 #include <opie2/osqlquery.h>
00038 
00039 #include <opie2/opimrecurrence.h>
00040 #include <opie2/odatebookaccessbackend_sql.h>
00041 #include <opie2/odebug.h>
00042 
00043 #include <qpe/global.h>
00044 
00045 /* QT */
00046 #include <qarray.h>
00047 #include <qstringlist.h>
00048 
00049 /* STD */
00050 #include <stdio.h>
00051 #include <stdlib.h>
00052 
00053 
00054 using namespace Opie::DB;
00055 
00056 namespace {
00060     class FindCustomQuery : public OSQLQuery {
00061     public:
00062         FindCustomQuery(int uid);
00063         FindCustomQuery(const QArray<int>& );
00064         ~FindCustomQuery();
00065         QString query()const;
00066     private:
00067         QString single()const;
00068         QString multi()const;
00069         QArray<int> m_uids;
00070         int m_uid;
00071     };
00072 
00073     FindCustomQuery::FindCustomQuery(int uid)
00074         : OSQLQuery(), m_uid( uid ) {
00075     }
00076     FindCustomQuery::FindCustomQuery(const QArray<int>& ints)
00077         : OSQLQuery(), m_uids( ints ){
00078     }
00079     FindCustomQuery::~FindCustomQuery() {
00080     }
00081     QString FindCustomQuery::query()const{
00082 //      if ( m_uids.count() == 0 )
00083             return single();
00084     }
00085     QString FindCustomQuery::single()const{
00086         QString qu = "select uid, type, value from custom_data where uid = ";
00087         qu += QString::number(m_uid);
00088         return qu;
00089     }
00090 }
00091 
00092 
00093 namespace Opie {
00094 
00095 
00096 ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& ,
00097                                                         const QString& fileName )
00098     : ODateBookAccessBackend(), m_driver( NULL )
00099 {
00100     m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName;
00101 
00102     // Get the standart sql-driver from the OSQLManager..
00103     OSQLManager man;
00104     m_driver = man.standard();
00105     m_driver->setUrl( m_fileName );
00106 
00107     initFields();
00108 
00109     load();
00110 }
00111 
00112 ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() {
00113     if( m_driver )
00114         delete m_driver;
00115 }
00116 
00117 void ODateBookAccessBackend_SQL::initFields()
00118 {
00119 
00120     // This map contains the translation of the fieldtype id's to
00121     // the names of the table columns
00122     m_fieldMap.insert( OPimEvent::FUid, "uid" );
00123     m_fieldMap.insert( OPimEvent::FCategories, "Categories" );
00124     m_fieldMap.insert( OPimEvent::FDescription, "Description" );
00125     m_fieldMap.insert( OPimEvent::FLocation, "Location" );
00126     m_fieldMap.insert( OPimEvent::FType, "Type" );
00127     m_fieldMap.insert( OPimEvent::FAlarm, "Alarm" );
00128     m_fieldMap.insert( OPimEvent::FSound, "Sound" );
00129     m_fieldMap.insert( OPimEvent::FRType, "RType" );
00130     m_fieldMap.insert( OPimEvent::FRWeekdays, "RWeekdays" );
00131     m_fieldMap.insert( OPimEvent::FRPosition, "RPosition" );
00132     m_fieldMap.insert( OPimEvent::FRFreq, "RFreq" );
00133     m_fieldMap.insert( OPimEvent::FRHasEndDate, "RHasEndDate" );
00134     m_fieldMap.insert( OPimEvent::FREndDate, "REndDate" );
00135     m_fieldMap.insert( OPimEvent::FRCreated, "RCreated" );
00136     m_fieldMap.insert( OPimEvent::FRExceptions, "RExceptions" );
00137     m_fieldMap.insert( OPimEvent::FStart, "Start" );
00138     m_fieldMap.insert( OPimEvent::FEnd, "End" );
00139     m_fieldMap.insert( OPimEvent::FNote, "Note" );
00140     m_fieldMap.insert( OPimEvent::FTimeZone, "TimeZone" );
00141     m_fieldMap.insert( OPimEvent::FRecParent, "RecParent" );
00142     m_fieldMap.insert( OPimEvent::FRecChildren, "Recchildren" );
00143 
00144     // Create a map that maps the column name to the id
00145     QMapConstIterator<int, QString> it;
00146     for ( it = m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){
00147         m_reverseFieldMap.insert( it.data(), it.key() );
00148     }
00149 
00150 }
00151 
00152 bool ODateBookAccessBackend_SQL::load()
00153 {
00154     if (!m_driver->open() )
00155         return false;
00156 
00157     // Don't expect that the database exists.
00158     // It is save here to create the table, even if it
00159     // do exist. ( Is that correct for all databases ?? )
00160     QString qu = "create table datebook( uid INTEGER PRIMARY KEY ";
00161 
00162     QMap<int, QString>::Iterator it;
00163     for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){
00164         qu += QString( ",%1 VARCHAR(10)" ).arg( it.data() );
00165     }
00166     qu += " );";
00167 
00168     qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR(10), priority INTEGER, value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );";
00169 
00170     OSQLRawQuery raw( qu );
00171     OSQLResult res = m_driver->query( &raw );
00172     if ( res.state() != OSQLResult::Success )
00173         return false;
00174 
00175     update();
00176 
00177     return true;
00178 }
00179 
00180 void ODateBookAccessBackend_SQL::update()
00181 {
00182 
00183     QString qu = "select uid from datebook";
00184     OSQLRawQuery raw( qu );
00185     OSQLResult res = m_driver->query( &raw );
00186     if ( res.state() != OSQLResult::Success ){
00187         // m_uids.clear();
00188         return;
00189     }
00190 
00191     m_uids = extractUids( res );
00192 
00193 }
00194 
00195 bool ODateBookAccessBackend_SQL::reload()
00196 {
00197     return load();
00198 }
00199 
00200 bool ODateBookAccessBackend_SQL::save()
00201 {
00202     return m_driver->close();  // Shouldn't m_driver->sync be better than close ? (eilers)
00203 }
00204 
00205 QArray<int> ODateBookAccessBackend_SQL::allRecords()const
00206 {
00207     return m_uids;
00208 }
00209 
00210 QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OPimEvent&, int,  const QDateTime& ) {
00211         qDebug( "Accessing ODateBookAccessBackend_SQL::queryByExample() which is not implemented!" );
00212     return QArray<int>();
00213 }
00214 
00215 void ODateBookAccessBackend_SQL::clear()
00216 {
00217     QString qu = "drop table datebook;";
00218     qu += "drop table custom_data;";
00219 
00220     OSQLRawQuery raw( qu );
00221     OSQLResult res = m_driver->query( &raw );
00222 
00223     reload();
00224 }
00225 
00226 
00227 OPimEvent ODateBookAccessBackend_SQL::find( int uid ) const{
00228     odebug << "ODateBookAccessBackend_SQL::find( " << uid << " )" << oendl;
00229 
00230     QString qu = "select *";
00231     qu += "from datebook where uid = " + QString::number(uid);
00232 
00233     odebug << "Query: " << qu << "" << oendl;
00234 
00235     OSQLRawQuery raw( qu );
00236     OSQLResult res = m_driver->query( &raw );
00237 
00238     OSQLResultItem resItem = res.first();
00239 
00240     // Create Map for date event and insert UID
00241     QMap<int,QString> dateEventMap;
00242     dateEventMap.insert( OPimEvent::FUid, QString::number( uid ) );
00243 
00244     // Now insert the data out of the columns into the map.
00245     QMapConstIterator<int, QString> it;
00246     for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){
00247         dateEventMap.insert( m_reverseFieldMap[*it], resItem.data( *it ) );
00248     }
00249 
00250     // Last step: Put map into date event, add custom map and return it
00251     OPimEvent retDate( dateEventMap );
00252     retDate.setExtraMap( requestCustom( uid ) );
00253 
00254     odebug << "ODateBookAccessBackend_SQL::find( " << uid << " ) end" << oendl;
00255     return retDate;
00256 }
00257 
00258 // FIXME: Speed up update of uid's..
00259 bool ODateBookAccessBackend_SQL::add( const OPimEvent& ev )
00260 {
00261     QMap<int,QString> eventMap = ev.toMap();
00262 
00263     QString qu = "insert into datebook VALUES( " + QString::number( ev.uid() );
00264     QMap<int, QString>::Iterator it;
00265     for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){
00266         if ( !eventMap[it.key()].isEmpty() )
00267             qu += QString( ",\"%1\"" ).arg( eventMap[it.key()] );
00268         else
00269             qu += QString( ",\"\"" );
00270     }
00271     qu += " );";
00272 
00273     // Add custom entries
00274     int id = 0;
00275     QMap<QString, QString> customMap = ev.toExtraMap();
00276     for( QMap<QString, QString>::Iterator it = customMap.begin();
00277          it != customMap.end(); ++it ){
00278         qu  += "insert into custom_data VALUES("
00279             +  QString::number( ev.uid() )
00280             + ","
00281             +  QString::number( id++ )
00282             + ",'"
00283             + it.key() //.latin1()
00284             + "',"
00285             + "0" // Priority for future enhancements
00286             + ",'"
00287             + it.data() //.latin1()
00288             + "');";
00289     }
00290 
00291     OSQLRawQuery raw( qu );
00292     OSQLResult res = m_driver->query( &raw );
00293     if ( res.state() != OSQLResult::Success ){
00294         return false;
00295     }
00296 
00297     // Update list of uid's
00298     update();
00299 
00300     return true;
00301 }
00302 
00303 // FIXME: Speed up update of uid's..
00304 bool ODateBookAccessBackend_SQL::remove( int uid )
00305 {
00306     QString qu = "DELETE from datebook where uid = "
00307         + QString::number( uid ) + ";";
00308     qu += "DELETE from custom_data where uid = "
00309         + QString::number( uid ) + ";";
00310 
00311     OSQLRawQuery raw( qu );
00312     OSQLResult res = m_driver->query( &raw );
00313     if ( res.state() != OSQLResult::Success ){
00314         return false;
00315     }
00316 
00317     // Update list of uid's
00318     update();
00319 
00320     return true;
00321 }
00322 
00323 bool ODateBookAccessBackend_SQL::replace( const OPimEvent& ev )
00324 {
00325     remove( ev.uid() );
00326     return add( ev );
00327 }
00328 
00329 
00330 QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const
00331 {
00332     QString qu = "select uid from datebook where RType!=\"\" AND RType!=\"NoRepeat\"";
00333     OSQLRawQuery raw( qu );
00334     OSQLResult res = m_driver->query( &raw );
00335     if ( res.state() != OSQLResult::Success ){
00336         QArray<int> nix;
00337         return nix;
00338     }
00339 
00340     return extractUids( res );
00341 }
00342 
00343 QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const
00344 {
00345     QString qu = "select uid from datebook where RType=\"\" or RType=\"NoRepeat\"";
00346     OSQLRawQuery raw( qu );
00347     OSQLResult res = m_driver->query( &raw );
00348     if ( res.state() != OSQLResult::Success ){
00349         QArray<int> nix;
00350         return nix;
00351     }
00352 
00353     return extractUids( res );
00354 }
00355 
00356 OPimEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats()const
00357 {
00358     QArray<int> nonRepUids = nonRepeats();
00359     OPimEvent::ValueList list;
00360 
00361     for (uint i = 0; i < nonRepUids.count(); ++i ){
00362         list.append( find( nonRepUids[i] ) );
00363     }
00364 
00365     return list;
00366 
00367 }
00368 OPimEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats()const
00369 {
00370     QArray<int> rawRepUids = rawRepeats();
00371     OPimEvent::ValueList list;
00372 
00373     for (uint i = 0; i < rawRepUids.count(); ++i ){
00374         list.append( find( rawRepUids[i] ) );
00375     }
00376 
00377     return list;
00378 }
00379 
00380 
00381 QArray<int> ODateBookAccessBackend_SQL::matchRegexp(  const QRegExp &r ) const
00382 {
00383 
00384     QString qu = "SELECT uid FROM datebook WHERE (";
00385 
00386     // Do it make sense to search other fields, too ?
00387     qu += " rlike(\""+ r.pattern() + "\", Location ) OR";
00388     qu += " rlike(\""+ r.pattern() + "\", Note )";
00389 
00390     qu += " )";
00391 
00392     odebug << "query: " << qu << "" << oendl;
00393 
00394     OSQLRawQuery raw( qu );
00395     OSQLResult res = m_driver->query( &raw );
00396 
00397     return extractUids( res );
00398 
00399 
00400 
00401 }
00402 
00403 /* ===== Private Functions ========================================== */
00404 
00405 QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const
00406 {
00407     QTime t;
00408     t.start();
00409     OSQLResultItem::ValueList list = res.results();
00410     OSQLResultItem::ValueList::Iterator it;
00411     QArray<int> ints(list.count() );
00412 
00413     int i = 0;
00414     for (it = list.begin(); it != list.end(); ++it ) {
00415         ints[i] =  (*it).data("uid").toInt();
00416         i++;
00417     }
00418 
00419     return ints;
00420 
00421 }
00422 
00423 QMap<QString, QString> ODateBookAccessBackend_SQL::requestCustom( int uid ) const
00424 {
00425     QTime t;
00426     t.start();
00427 
00428     QMap<QString, QString> customMap;
00429 
00430     FindCustomQuery query( uid );
00431     OSQLResult res_custom = m_driver->query( &query );
00432 
00433     if ( res_custom.state() == OSQLResult::Failure ) {
00434         QMap<QString, QString> empty;
00435         return empty;
00436     }
00437 
00438     OSQLResultItem::ValueList list = res_custom.results();
00439     OSQLResultItem::ValueList::Iterator it = list.begin();
00440     for ( ; it != list.end(); ++it ) {
00441         customMap.insert( (*it).data( "type" ), (*it).data( "value" ) );
00442     }
00443 
00444     odebug << "RequestCustom needed: " << t.elapsed() << " ms" << oendl;
00445     return customMap;
00446 }
00447 
00448 
00449 }

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