summaryrefslogtreecommitdiff
path: root/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
Unidiff
Diffstat (limited to 'libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp664
1 files changed, 664 insertions, 0 deletions
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
new file mode 100644
index 0000000..4afa5f3
--- a/dev/null
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
@@ -0,0 +1,664 @@
1/*
2 * SQL Backend for the OPIE-Contact Database.
3 *
4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
5 *
6 * =====================================================================
7 *This program is free software; you can redistribute it and/or
8 *modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 * =====================================================================
12 * =====================================================================
13 * Version: $Id$
14 * =====================================================================
15 * History:
16 * $Log$
17 * Revision 1.1 2003/09/22 14:31:16 eilers
18 * Added first experimental incarnation of sql-backend for addressbook.
19 * Some modifications to be able to compile the todo sql-backend.
20 * A lot of changes fill follow...
21 *
22 */
23
24#include "ocontactaccessbackend_sql.h"
25
26#include <qarray.h>
27#include <qdatetime.h>
28#include <qstringlist.h>
29
30#include <qpe/global.h>
31#include <qpe/recordfields.h>
32
33#include <opie/ocontactfields.h>
34#include <opie/oconversion.h>
35#include <opie2/osqldriver.h>
36#include <opie2/osqlresult.h>
37#include <opie2/osqlmanager.h>
38#include <opie2/osqlquery.h>
39
40/*
41 * Implementation of used query types
42 * CREATE query
43 * LOAD query
44 * INSERT
45 * REMOVE
46 * CLEAR
47 */
48namespace {
49 /**
50 * CreateQuery for the Todolist Table
51 */
52 class CreateQuery : public OSQLQuery {
53 public:
54 CreateQuery();
55 ~CreateQuery();
56 QString query()const;
57 };
58
59 /**
60 * Clears (delete) a Table
61 */
62 class ClearQuery : public OSQLQuery {
63 public:
64 ClearQuery();
65 ~ClearQuery();
66 QString query()const;
67
68 };
69
70
71 /**
72 * LoadQuery
73 * this one queries for all uids
74 */
75 class LoadQuery : public OSQLQuery {
76 public:
77 LoadQuery();
78 ~LoadQuery();
79 QString query()const;
80 };
81
82 /**
83 * inserts/adds a OContact to the table
84 */
85 class InsertQuery : public OSQLQuery {
86 public:
87 InsertQuery(const OContact& );
88 ~InsertQuery();
89 QString query()const;
90 private:
91 OContact m_contact;
92 };
93
94
95 /**
96 * removes one from the table
97 */
98 class RemoveQuery : public OSQLQuery {
99 public:
100 RemoveQuery(int uid );
101 ~RemoveQuery();
102 QString query()const;
103 private:
104 int m_uid;
105 };
106
107 /**
108 * a find query for noncustom elements
109 */
110 class FindQuery : public OSQLQuery {
111 public:
112 FindQuery(int uid);
113 FindQuery(const QArray<int>& );
114 ~FindQuery();
115 QString query()const;
116 private:
117 QString single()const;
118 QString multi()const;
119 QArray<int> m_uids;
120 int m_uid;
121 };
122
123 /**
124 * a find query for custom elements
125 */
126 class FindCustomQuery : public OSQLQuery {
127 public:
128 FindCustomQuery(int uid);
129 FindCustomQuery(const QArray<int>& );
130 ~FindCustomQuery();
131 QString query()const;
132 private:
133 QString single()const;
134 QString multi()const;
135 QArray<int> m_uids;
136 int m_uid;
137 };
138
139
140
141 // We using three tables to store the information:
142 // 1. addressbook : It contains General information about the contact (non custom)
143 // 2. dates : Stuff like birthdays, anniversaries, etc.
144 // 3. custom_data : Not official supported entries
145 // All tables are connected by the uid of the contact.
146 // Maybe I should add a table for meta-information ?
147 CreateQuery::CreateQuery() : OSQLQuery() {}
148 CreateQuery::~CreateQuery() {}
149 QString CreateQuery::query()const {
150 QString qu;
151 qu += "create table addressbook( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id));";
152 qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );";
153 // qu += "create table dates( uid PRIMARY KEY, type, day, month, year, hour, minute, second );";
154 return qu;
155 }
156
157 ClearQuery::ClearQuery()
158 : OSQLQuery() {}
159 ClearQuery::~ClearQuery() {}
160 QString ClearQuery::query()const {
161 QString qu = "drop table addressbook;";
162 qu += "drop table custom_data;";
163 qu += "drop table dates;";
164 return qu;
165 }
166
167// Distinct loading is not very fast. If I expect that every person has just
168// one (and always one) 'Last Name', I can request all uid's for existing lastnames,
169// which is faster..
170// But this may not be true for all entries, like company contacts..
171// The current AddressBook application handles this problem, but other may not.. (eilers)
172#define __USE_SUPERFAST_LOADQUERY
173
174 LoadQuery::LoadQuery() : OSQLQuery() {}
175 LoadQuery::~LoadQuery() {}
176 QString LoadQuery::query()const {
177 QString qu;
178#ifndef __USE_SUPERFAST_LOADQUERY
179 qu += "select distinct uid from addressbook";
180#else
181 qu += "select uid from addressbook where type = 'Last Name'";
182#endif
183
184 return qu;
185 }
186
187
188 InsertQuery::InsertQuery( const OContact& contact )
189 : OSQLQuery(), m_contact( contact ) {
190 }
191
192 InsertQuery::~InsertQuery() {
193 }
194
195 /*
196 * converts from a OContact to a query
197 */
198 QString InsertQuery::query()const{
199
200 // Get all information out of the contact-class
201 // Remember: The category is stored in contactMap, too !
202 QMap<int, QString> contactMap = m_contact.toMap();
203 QMap<QString, QString> customMap = m_contact.toExtraMap();
204
205 QMap<QString, QString> addressbook_db;
206
207 // Get the translation from the ID to the String
208 QMap<int, QString> transMap = OContactFields::idToUntrFields();
209
210 for( QMap<int, QString>::Iterator it = contactMap.begin();
211 it != contactMap.end(); ++it ){
212 switch ( it.key() ){
213 case Qtopia::Birthday:{
214 // These entries should stored in a special format
215 // year-month-day
216 QDate day = m_contact.birthday();
217 addressbook_db.insert( transMap[it.key()],
218 QString("%1-%2-%3")
219 .arg( day.year() )
220 .arg( day.month() )
221 .arg( day.day() ) );
222 }
223 break;
224 case Qtopia::Anniversary:{
225 // These entries should stored in a special format
226 // year-month-day
227 QDate day = m_contact.anniversary();
228 addressbook_db.insert( transMap[it.key()],
229 QString("%1-%2-%3")
230 .arg( day.year() )
231 .arg( day.month() )
232 .arg( day.day() ) );
233 }
234 break;
235 case Qtopia::AddressUid: // Ignore UID
236 break;
237 default: // Translate id to String
238 addressbook_db.insert( transMap[it.key()], it.data() );
239 break;
240 }
241
242 }
243
244 // Now convert this whole stuff into a SQL String, beginning with
245 // the addressbook table..
246 QString qu;
247 // qu += "begin transaction;";
248 int id = 0;
249 for( QMap<QString, QString>::Iterator it = addressbook_db.begin();
250 it != addressbook_db.end(); ++it ){
251 qu += "insert into addressbook VALUES("
252 + QString::number( m_contact.uid() )
253 + ","
254 + QString::number( id++ )
255 + ",'"
256 + it.key() //.latin1()
257 + "',"
258 + "0" // Priority for future enhancements
259 + ",'"
260 + it.data() //.latin1()
261 + "');";
262 }
263
264 // Now add custom data..
265 id = 0;
266 for( QMap<QString, QString>::Iterator it = customMap.begin();
267 it != customMap.end(); ++it ){
268 qu += "insert into custom_data VALUES("
269 + QString::number( m_contact.uid() )
270 + ","
271 + QString::number( id++ )
272 + ",'"
273 + it.key() //.latin1()
274 + "',"
275 + "0" // Priority for future enhancements
276 + ",'"
277 + it.data() //.latin1()
278 + "');";
279 }
280
281 // qu += "commit;";
282 qWarning("add %s", qu.latin1() );
283 return qu;
284 }
285
286
287 RemoveQuery::RemoveQuery(int uid )
288 : OSQLQuery(), m_uid( uid ) {}
289 RemoveQuery::~RemoveQuery() {}
290 QString RemoveQuery::query()const {
291 QString qu = "DELETE from addressbook where uid = "
292 + QString::number(m_uid) + ";";
293 qu += "DELETE from dates where uid = "
294 + QString::number(m_uid) + ";";
295 qu += "DELETE from custom_data where uid = "
296 + QString::number(m_uid) + ";";
297 return qu;
298 }
299
300
301
302
303 FindQuery::FindQuery(int uid)
304 : OSQLQuery(), m_uid( uid ) {
305 }
306 FindQuery::FindQuery(const QArray<int>& ints)
307 : OSQLQuery(), m_uids( ints ){
308 }
309 FindQuery::~FindQuery() {
310 }
311 QString FindQuery::query()const{
312 // if ( m_uids.count() == 0 )
313 return single();
314 }
315 /*
316 else
317 return multi();
318 }
319 QString FindQuery::multi()const {
320 QString qu = "select uid, type, value from addressbook where";
321 for (uint i = 0; i < m_uids.count(); i++ ) {
322 qu += " UID = " + QString::number( m_uids[i] ) + " OR";
323 }
324 qu.remove( qu.length()-2, 2 ); // Hmmmm..
325 return qu;
326 }
327 */
328 QString FindQuery::single()const{
329 QString qu = "select uid, type, value from addressbook where uid = ";
330 qu += QString::number(m_uid);
331 return qu;
332 }
333
334
335 FindCustomQuery::FindCustomQuery(int uid)
336 : OSQLQuery(), m_uid( uid ) {
337 }
338 FindCustomQuery::FindCustomQuery(const QArray<int>& ints)
339 : OSQLQuery(), m_uids( ints ){
340 }
341 FindCustomQuery::~FindCustomQuery() {
342 }
343 QString FindCustomQuery::query()const{
344 // if ( m_uids.count() == 0 )
345 return single();
346 }
347 QString FindCustomQuery::single()const{
348 QString qu = "select uid, type, value from custom_data where uid = ";
349 qu += QString::number(m_uid);
350 return qu;
351 }
352
353};
354
355
356/* --------------------------------------------------------------------------- */
357
358OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */,
359 const QString& filename ): m_changed(false)
360{
361 qWarning("C'tor OContactAccessBackend_SQL starts");
362 QTime t;
363 t.start();
364
365 /* Expecting to access the default filename if nothing else is set */
366 if ( filename.isEmpty() ){
367 m_fileName = Global::applicationFileName( "addressbook","addressbook.db" );
368 } else
369 m_fileName = filename;
370
371 // Get the standart sql-driver from the OSQLManager..
372 OSQLManager man;
373 m_driver = man.standard();
374 m_driver->setUrl( m_fileName );
375
376 load();
377
378 qWarning("C'tor OContactAccessBackend_SQL ends: %d", t.elapsed() );
379}
380
381
382bool OContactAccessBackend_SQL::load ()
383{
384 if (!m_driver->open() )
385 return false;
386
387 // Don't expect that the database exists.
388 // It is save here to create the table, even if it
389 // do exist. ( Is that correct for all databases ?? )
390 CreateQuery creat;
391 OSQLResult res = m_driver->query( &creat );
392
393 update();
394
395 return true;
396
397}
398
399bool OContactAccessBackend_SQL::reload()
400{
401 return load();
402}
403
404bool OContactAccessBackend_SQL::save()
405{
406 return m_driver->close();
407}
408
409
410void OContactAccessBackend_SQL::clear ()
411{
412 ClearQuery cle;
413 OSQLResult res = m_driver->query( &cle );
414 CreateQuery qu;
415 res = m_driver->query(&qu);
416}
417
418bool OContactAccessBackend_SQL::wasChangedExternally()
419{
420 return false;
421}
422
423QArray<int> OContactAccessBackend_SQL::allRecords() const
424{
425
426 // FIXME: Think about cute handling of changed tables..
427 // Thus, we don't have to call update here...
428 if ( m_changed )
429 ((OContactAccessBackend_SQL*)this)->update();
430
431 return m_uids;
432}
433
434bool OContactAccessBackend_SQL::add ( const OContact &newcontact )
435{
436 InsertQuery ins( newcontact );
437 OSQLResult res = m_driver->query( &ins );
438
439 if ( res.state() == OSQLResult::Failure )
440 return false;
441
442 int c = m_uids.count();
443 m_uids.resize( c+1 );
444 m_uids[c] = newcontact.uid();
445
446 return true;
447}
448
449
450bool OContactAccessBackend_SQL::remove ( int uid )
451{
452 RemoveQuery rem( uid );
453 OSQLResult res = m_driver->query(&rem );
454
455 if ( res.state() == OSQLResult::Failure )
456 return false;
457
458 m_changed = true;
459
460 return true;
461}
462
463bool OContactAccessBackend_SQL::replace ( const OContact &contact )
464{
465 if ( !remove( contact.uid() ) )
466 return false;
467
468 return add( contact );
469}
470
471
472OContact OContactAccessBackend_SQL::find ( int uid ) const
473{
474 qWarning("OContactAccessBackend_SQL::find()");
475 QTime t;
476 t.start();
477
478 OContact retContact( requestNonCustom( uid ) );
479 retContact.setExtraMap( requestCustom( uid ) );
480
481 qWarning("OContactAccessBackend_SQL::find() needed: %d", t.elapsed() );
482 return retContact;
483}
484
485
486
487QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() )
488{
489 QArray<int> nix(0);
490 return nix;
491}
492
493QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const
494{
495 QArray<int> nix(0);
496 return nix;
497}
498
499const uint OContactAccessBackend_SQL::querySettings()
500{
501 return 0;
502}
503
504bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const
505{
506 return false;
507}
508
509QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int )
510{
511 QTime t;
512 t.start();
513
514 // Not implemented..
515 QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' ";
516
517 query += "ORDER BY value ";
518 if ( !asc )
519 query += "DESC";
520
521 qWarning("sorted query is: %s", query.latin1() );
522
523 OSQLRawQuery raw( query );
524 OSQLResult res = m_driver->query( &raw );
525 if ( res.state() != OSQLResult::Success ){
526 QArray<int> empty;
527 return empty;
528 }
529
530 QArray<int> list = extractUids( res );
531
532 qWarning("sorted needed %d ms!", t.elapsed() );
533 return list;
534}
535
536
537void OContactAccessBackend_SQL::update()
538{
539 qWarning("Update starts");
540 QTime t;
541 t.start();
542
543 // Now load the database set and extract the uid's
544 // which will be held locally
545
546 LoadQuery lo;
547 OSQLResult res = m_driver->query(&lo);
548 if ( res.state() != OSQLResult::Success )
549 return;
550
551 m_uids = extractUids( res );
552
553 m_changed = false;
554
555 qWarning("Update ends %d", t.elapsed() );
556}
557
558QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const
559{
560 qWarning("extractUids");
561 QTime t;
562 t.start();
563 OSQLResultItem::ValueList list = res.results();
564 OSQLResultItem::ValueList::Iterator it;
565 QArray<int> ints(list.count() );
566 qWarning(" count = %d", list.count() );
567
568 int i = 0;
569 for (it = list.begin(); it != list.end(); ++it ) {
570 ints[i] = (*it).data("uid").toInt();
571 i++;
572 }
573 qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() );
574
575 return ints;
576
577}
578
579QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const
580{
581 QTime t;
582 t.start();
583
584 QMap<int, QString> nonCustomMap;
585
586 int t2needed = 0;
587 QTime t2;
588 t2.start();
589 FindQuery query( uid );
590 OSQLResult res_noncustom = m_driver->query( &query );
591 t2needed = t2.elapsed();
592
593 if ( res_noncustom.state() == OSQLResult::Failure ) {
594 qWarning("OSQLResult::Failure in find query !!");
595 QMap<int, QString> empty;
596 return empty;
597 }
598
599 int t3needed = 0;
600 QTime t3;
601 t3.start();
602 QMap<QString, int> translateMap = OContactFields::untrFieldsToId();
603
604 OSQLResultItem::ValueList list = res_noncustom.results();
605 OSQLResultItem::ValueList::Iterator it = list.begin();
606 for ( ; it != list.end(); ++it ) {
607 if ( (*it).data("type") != "" ){
608 int typeId = translateMap[(*it).data( "type" )];
609 switch( typeId ){
610 case Qtopia::Birthday:
611 case Qtopia::Anniversary:{
612 // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
613 QStringList list = QStringList::split( '-', (*it).data( "value" ) );
614 QStringList::Iterator lit = list.begin();
615 int year = (*lit).toInt();
616 qWarning("1. %s", (*lit).latin1());
617 int month = (*(++lit)).toInt();
618 qWarning("2. %s", (*lit).latin1());
619 int day = (*(++lit)).toInt();
620 qWarning("3. %s", (*lit).latin1());
621 qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day );
622 QDate date( year, month, day );
623 nonCustomMap.insert( typeId, OConversion::dateToString( date ) );
624 }
625 break;
626 default:
627 nonCustomMap.insert( typeId,
628 (*it).data( "value" ) );
629 }
630 }
631 }
632 // Add UID to Map..
633 nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) );
634 t3needed = t3.elapsed();
635
636 qWarning("RequestNonCustom needed: ins:%d, query: %d, mapping: %d", t.elapsed(), t2needed, t3needed );
637 return nonCustomMap;
638}
639
640QMap<QString, QString> OContactAccessBackend_SQL::requestCustom( int uid ) const
641{
642 QTime t;
643 t.start();
644
645 QMap<QString, QString> customMap;
646
647 FindCustomQuery query( uid );
648 OSQLResult res_custom = m_driver->query( &query );
649
650 if ( res_custom.state() == OSQLResult::Failure ) {
651 qWarning("OSQLResult::Failure in find query !!");
652 QMap<QString, QString> empty;
653 return empty;
654 }
655
656 OSQLResultItem::ValueList list = res_custom.results();
657 OSQLResultItem::ValueList::Iterator it = list.begin();
658 for ( ; it != list.end(); ++it ) {
659 customMap.insert( (*it).data( "type" ), (*it).data( "value" ) );
660 }
661
662 qWarning("RequestCustom needed: %d", t.elapsed() );
663 return customMap;
664}