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.cpp313
1 files changed, 285 insertions, 28 deletions
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
index 4afa5f3..132c9fc 100644
--- a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
@@ -1,63 +1,84 @@
1/* 1/*
2 * SQL Backend for the OPIE-Contact Database. 2 * SQL Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
5 * 5 *
6 * ===================================================================== 6 * =====================================================================
7 *This program is free software; you can redistribute it and/or 7 *This program is free software; you can redistribute it and/or
8 *modify it under the terms of the GNU Library General Public 8 *modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
11 * ===================================================================== 11 * =====================================================================
12 * ===================================================================== 12 * =====================================================================
13 * Version: $Id$ 13 * Version: $Id$
14 * ===================================================================== 14 * =====================================================================
15 * History: 15 * History:
16 * $Log$ 16 * $Log$
17 * Revision 1.2 2003/09/29 07:44:26 eilers
18 * Improvement of PIM-SQL Databases, but search queries are still limited.
19 * Addressbook: Changed table layout. Now, we just need 1/3 of disk-space.
20 * Todo: Started to add new attributes. Some type conversions missing.
21 *
17 * Revision 1.1 2003/09/22 14:31:16 eilers 22 * Revision 1.1 2003/09/22 14:31:16 eilers
18 * Added first experimental incarnation of sql-backend for addressbook. 23 * Added first experimental incarnation of sql-backend for addressbook.
19 * Some modifications to be able to compile the todo sql-backend. 24 * Some modifications to be able to compile the todo sql-backend.
20 * A lot of changes fill follow... 25 * A lot of changes fill follow...
21 * 26 *
22 */ 27 */
23 28
24#include "ocontactaccessbackend_sql.h" 29#include "ocontactaccessbackend_sql.h"
25 30
26#include <qarray.h> 31#include <qarray.h>
27#include <qdatetime.h> 32#include <qdatetime.h>
28#include <qstringlist.h> 33#include <qstringlist.h>
29 34
30#include <qpe/global.h> 35#include <qpe/global.h>
31#include <qpe/recordfields.h> 36#include <qpe/recordfields.h>
32 37
33#include <opie/ocontactfields.h> 38#include <opie/ocontactfields.h>
34#include <opie/oconversion.h> 39#include <opie/oconversion.h>
35#include <opie2/osqldriver.h> 40#include <opie2/osqldriver.h>
36#include <opie2/osqlresult.h> 41#include <opie2/osqlresult.h>
37#include <opie2/osqlmanager.h> 42#include <opie2/osqlmanager.h>
38#include <opie2/osqlquery.h> 43#include <opie2/osqlquery.h>
39 44
45
46
47
48// If defined, we use a horizontal table ( uid, attr1, attr2, attr3, ..., attrn ) instead
49// vertical like "uid, type, value".
50// DON'T DEACTIVATE THIS DEFINE IN PRODUCTIVE ENVIRONMENTS !!
51#define __STORE_HORIZONTAL_
52
53// Distinct loading is not very fast. If I expect that every person has just
54// one (and always one) 'Last Name', I can request all uid's for existing lastnames,
55// which is faster..
56// But this may not be true for all entries, like company contacts..
57// The current AddressBook application handles this problem, but other may not.. (eilers)
58#define __USE_SUPERFAST_LOADQUERY
59
60
40/* 61/*
41 * Implementation of used query types 62 * Implementation of used query types
42 * CREATE query 63 * CREATE query
43 * LOAD query 64 * LOAD query
44 * INSERT 65 * INSERT
45 * REMOVE 66 * REMOVE
46 * CLEAR 67 * CLEAR
47 */ 68 */
48namespace { 69namespace {
49 /** 70 /**
50 * CreateQuery for the Todolist Table 71 * CreateQuery for the Todolist Table
51 */ 72 */
52 class CreateQuery : public OSQLQuery { 73 class CreateQuery : public OSQLQuery {
53 public: 74 public:
54 CreateQuery(); 75 CreateQuery();
55 ~CreateQuery(); 76 ~CreateQuery();
56 QString query()const; 77 QString query()const;
57 }; 78 };
58 79
59 /** 80 /**
60 * Clears (delete) a Table 81 * Clears (delete) a Table
61 */ 82 */
62 class ClearQuery : public OSQLQuery { 83 class ClearQuery : public OSQLQuery {
63 public: 84 public:
@@ -119,109 +140,174 @@ namespace {
119 QArray<int> m_uids; 140 QArray<int> m_uids;
120 int m_uid; 141 int m_uid;
121 }; 142 };
122 143
123 /** 144 /**
124 * a find query for custom elements 145 * a find query for custom elements
125 */ 146 */
126 class FindCustomQuery : public OSQLQuery { 147 class FindCustomQuery : public OSQLQuery {
127 public: 148 public:
128 FindCustomQuery(int uid); 149 FindCustomQuery(int uid);
129 FindCustomQuery(const QArray<int>& ); 150 FindCustomQuery(const QArray<int>& );
130 ~FindCustomQuery(); 151 ~FindCustomQuery();
131 QString query()const; 152 QString query()const;
132 private: 153 private:
133 QString single()const; 154 QString single()const;
134 QString multi()const; 155 QString multi()const;
135 QArray<int> m_uids; 156 QArray<int> m_uids;
136 int m_uid; 157 int m_uid;
137 }; 158 };
138 159
139 160
140 161
141 // We using three tables to store the information: 162 // We using three tables to store the information:
142 // 1. addressbook : It contains General information about the contact (non custom) 163 // 1. addressbook : It contains General information about the contact (non custom)
143 // 2. dates : Stuff like birthdays, anniversaries, etc. 164 // 2. custom_data : Not official supported entries
144 // 3. custom_data : Not official supported entries
145 // All tables are connected by the uid of the contact. 165 // All tables are connected by the uid of the contact.
146 // Maybe I should add a table for meta-information ? 166 // Maybe I should add a table for meta-information ?
147 CreateQuery::CreateQuery() : OSQLQuery() {} 167 CreateQuery::CreateQuery() : OSQLQuery() {}
148 CreateQuery::~CreateQuery() {} 168 CreateQuery::~CreateQuery() {}
149 QString CreateQuery::query()const { 169 QString CreateQuery::query()const {
150 QString qu; 170 QString qu;
171#ifdef __STORE_HORIZONTAL_
172
173 qu += "create table addressbook( uid PRIMARY KEY ";
174
175 QStringList fieldList = OContactFields::untrfields( false );
176 for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
177 qu += QString( ",\"%1\" VARCHAR(10)" ).arg( *it );
178 }
179 qu += " );";
180
181 qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );";
182
183#else
184
151 qu += "create table addressbook( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id));"; 185 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) );"; 186 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 );"; 187 // qu += "create table dates( uid PRIMARY KEY, type, day, month, year, hour, minute, second );";
188
189#endif // __STORE_HORIZONTAL_
154 return qu; 190 return qu;
155 } 191 }
156 192
157 ClearQuery::ClearQuery() 193 ClearQuery::ClearQuery()
158 : OSQLQuery() {} 194 : OSQLQuery() {}
159 ClearQuery::~ClearQuery() {} 195 ClearQuery::~ClearQuery() {}
160 QString ClearQuery::query()const { 196 QString ClearQuery::query()const {
161 QString qu = "drop table addressbook;"; 197 QString qu = "drop table addressbook;";
162 qu += "drop table custom_data;"; 198 qu += "drop table custom_data;";
163 qu += "drop table dates;"; 199 // qu += "drop table dates;";
164 return qu; 200 return qu;
165 } 201 }
166 202
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 203
174 LoadQuery::LoadQuery() : OSQLQuery() {} 204 LoadQuery::LoadQuery() : OSQLQuery() {}
175 LoadQuery::~LoadQuery() {} 205 LoadQuery::~LoadQuery() {}
176 QString LoadQuery::query()const { 206 QString LoadQuery::query()const {
177 QString qu; 207 QString qu;
178#ifndef __USE_SUPERFAST_LOADQUERY 208#ifdef __STORE_HORIZONTAL_
179 qu += "select distinct uid from addressbook"; 209 qu += "select uid from addressbook";
180#else 210#else
211# ifndef __USE_SUPERFAST_LOADQUERY
212 qu += "select distinct uid from addressbook";
213# else
181 qu += "select uid from addressbook where type = 'Last Name'"; 214 qu += "select uid from addressbook where type = 'Last Name'";
182#endif 215# endif // __USE_SUPERFAST_LOADQUERY
216#endif // __STORE_HORIZONTAL_
183 217
184 return qu; 218 return qu;
185 } 219 }
186 220
187 221
188 InsertQuery::InsertQuery( const OContact& contact ) 222 InsertQuery::InsertQuery( const OContact& contact )
189 : OSQLQuery(), m_contact( contact ) { 223 : OSQLQuery(), m_contact( contact ) {
190 } 224 }
191 225
192 InsertQuery::~InsertQuery() { 226 InsertQuery::~InsertQuery() {
193 } 227 }
194 228
195 /* 229 /*
196 * converts from a OContact to a query 230 * converts from a OContact to a query
197 */ 231 */
198 QString InsertQuery::query()const{ 232 QString InsertQuery::query()const{
199 233
234#ifdef __STORE_HORIZONTAL_
235 QString qu;
236 qu += "insert into addressbook VALUES( " +
237 QString::number( m_contact.uid() );
238
239 // Get all information out of the contact-class
240 // Remember: The category is stored in contactMap, too !
241 QMap<int, QString> contactMap = m_contact.toMap();
242
243 QStringList fieldList = OContactFields::untrfields( false );
244 QMap<QString, int> translate = OContactFields::untrFieldsToId();
245 for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
246 // Convert Column-String to Id and get value for this id..
247 // Hmmm.. Maybe not very cute solution..
248 int id = translate[*it];
249 switch ( id ){
250 case Qtopia::Birthday:{
251 // These entries should stored in a special format
252 // year-month-day
253 QDate day = m_contact.birthday();
254 if ( day.isValid() ){
255 qu += QString(",\"%1-%2-%3\"")
256 .arg( day.year() )
257 .arg( day.month() )
258 .arg( day.day() );
259 } else {
260 qu += ",\"\"";
261 }
262 }
263 break;
264 case Qtopia::Anniversary:{
265 // These entries should stored in a special format
266 // year-month-day
267 QDate day = m_contact.anniversary();
268 if ( day.isValid() ){
269 qu += QString(",\"%1-%2-%3\"")
270 .arg( day.year() )
271 .arg( day.month() )
272 .arg( day.day() );
273 } else {
274 qu += ",\"\"";
275 }
276 }
277 break;
278
279 default:
280 qu += QString( ",\"%1\"" ).arg( contactMap[id] );
281 }
282 }
283 qu += " );";
284
285
286#else
200 // Get all information out of the contact-class 287 // Get all information out of the contact-class
201 // Remember: The category is stored in contactMap, too ! 288 // Remember: The category is stored in contactMap, too !
202 QMap<int, QString> contactMap = m_contact.toMap(); 289 QMap<int, QString> contactMap = m_contact.toMap();
203 QMap<QString, QString> customMap = m_contact.toExtraMap();
204 290
205 QMap<QString, QString> addressbook_db; 291 QMap<QString, QString> addressbook_db;
206 292
207 // Get the translation from the ID to the String 293 // Get the translation from the ID to the String
208 QMap<int, QString> transMap = OContactFields::idToUntrFields(); 294 QMap<int, QString> transMap = OContactFields::idToUntrFields();
209 295
210 for( QMap<int, QString>::Iterator it = contactMap.begin(); 296 for( QMap<int, QString>::Iterator it = contactMap.begin();
211 it != contactMap.end(); ++it ){ 297 it != contactMap.end(); ++it ){
212 switch ( it.key() ){ 298 switch ( it.key() ){
213 case Qtopia::Birthday:{ 299 case Qtopia::Birthday:{
214 // These entries should stored in a special format 300 // These entries should stored in a special format
215 // year-month-day 301 // year-month-day
216 QDate day = m_contact.birthday(); 302 QDate day = m_contact.birthday();
217 addressbook_db.insert( transMap[it.key()], 303 addressbook_db.insert( transMap[it.key()],
218 QString("%1-%2-%3") 304 QString("%1-%2-%3")
219 .arg( day.year() ) 305 .arg( day.year() )
220 .arg( day.month() ) 306 .arg( day.month() )
221 .arg( day.day() ) ); 307 .arg( day.day() ) );
222 } 308 }
223 break; 309 break;
224 case Qtopia::Anniversary:{ 310 case Qtopia::Anniversary:{
225 // These entries should stored in a special format 311 // These entries should stored in a special format
226 // year-month-day 312 // year-month-day
227 QDate day = m_contact.anniversary(); 313 QDate day = m_contact.anniversary();
@@ -240,163 +326,175 @@ namespace {
240 } 326 }
241 327
242 } 328 }
243 329
244 // Now convert this whole stuff into a SQL String, beginning with 330 // Now convert this whole stuff into a SQL String, beginning with
245 // the addressbook table.. 331 // the addressbook table..
246 QString qu; 332 QString qu;
247 // qu += "begin transaction;"; 333 // qu += "begin transaction;";
248 int id = 0; 334 int id = 0;
249 for( QMap<QString, QString>::Iterator it = addressbook_db.begin(); 335 for( QMap<QString, QString>::Iterator it = addressbook_db.begin();
250 it != addressbook_db.end(); ++it ){ 336 it != addressbook_db.end(); ++it ){
251 qu += "insert into addressbook VALUES(" 337 qu += "insert into addressbook VALUES("
252 + QString::number( m_contact.uid() ) 338 + QString::number( m_contact.uid() )
253 + "," 339 + ","
254 + QString::number( id++ ) 340 + QString::number( id++ )
255 + ",'" 341 + ",'"
256 + it.key() //.latin1() 342 + it.key() //.latin1()
257 + "'," 343 + "',"
258 + "0" // Priority for future enhancements 344 + "0" // Priority for future enhancements
259 + ",'" 345 + ",'"
260 + it.data() //.latin1() 346 + it.data() //.latin1()
261 + "');"; 347 + "');";
262 } 348 }
263 349
350 #endif //__STORE_HORIZONTAL_
264 // Now add custom data.. 351 // Now add custom data..
352#ifdef __STORE_HORIZONTAL_
353 int id = 0;
354#endif
265 id = 0; 355 id = 0;
356 QMap<QString, QString> customMap = m_contact.toExtraMap();
266 for( QMap<QString, QString>::Iterator it = customMap.begin(); 357 for( QMap<QString, QString>::Iterator it = customMap.begin();
267 it != customMap.end(); ++it ){ 358 it != customMap.end(); ++it ){
268 qu += "insert into custom_data VALUES(" 359 qu += "insert into custom_data VALUES("
269 + QString::number( m_contact.uid() ) 360 + QString::number( m_contact.uid() )
270 + "," 361 + ","
271 + QString::number( id++ ) 362 + QString::number( id++ )
272 + ",'" 363 + ",'"
273 + it.key() //.latin1() 364 + it.key() //.latin1()
274 + "'," 365 + "',"
275 + "0" // Priority for future enhancements 366 + "0" // Priority for future enhancements
276 + ",'" 367 + ",'"
277 + it.data() //.latin1() 368 + it.data() //.latin1()
278 + "');"; 369 + "');";
279 } 370 }
280
281 // qu += "commit;"; 371 // qu += "commit;";
282 qWarning("add %s", qu.latin1() ); 372 qWarning("add %s", qu.latin1() );
283 return qu; 373 return qu;
284 } 374 }
285 375
286 376
287 RemoveQuery::RemoveQuery(int uid ) 377 RemoveQuery::RemoveQuery(int uid )
288 : OSQLQuery(), m_uid( uid ) {} 378 : OSQLQuery(), m_uid( uid ) {}
289 RemoveQuery::~RemoveQuery() {} 379 RemoveQuery::~RemoveQuery() {}
290 QString RemoveQuery::query()const { 380 QString RemoveQuery::query()const {
291 QString qu = "DELETE from addressbook where uid = " 381 QString qu = "DELETE from addressbook where uid = "
292 + QString::number(m_uid) + ";"; 382 + QString::number(m_uid) + ";";
293 qu += "DELETE from dates where uid = "
294 + QString::number(m_uid) + ";";
295 qu += "DELETE from custom_data where uid = " 383 qu += "DELETE from custom_data where uid = "
296 + QString::number(m_uid) + ";"; 384 + QString::number(m_uid) + ";";
297 return qu; 385 return qu;
298 } 386 }
299 387
300 388
301 389
302 390
303 FindQuery::FindQuery(int uid) 391 FindQuery::FindQuery(int uid)
304 : OSQLQuery(), m_uid( uid ) { 392 : OSQLQuery(), m_uid( uid ) {
305 } 393 }
306 FindQuery::FindQuery(const QArray<int>& ints) 394 FindQuery::FindQuery(const QArray<int>& ints)
307 : OSQLQuery(), m_uids( ints ){ 395 : OSQLQuery(), m_uids( ints ){
308 } 396 }
309 FindQuery::~FindQuery() { 397 FindQuery::~FindQuery() {
310 } 398 }
311 QString FindQuery::query()const{ 399 QString FindQuery::query()const{
312 // if ( m_uids.count() == 0 ) 400 // if ( m_uids.count() == 0 )
313 return single(); 401 return single();
314 } 402 }
315 /* 403 /*
316 else 404 else
317 return multi(); 405 return multi();
318 } 406 }
319 QString FindQuery::multi()const { 407 QString FindQuery::multi()const {
320 QString qu = "select uid, type, value from addressbook where"; 408 QString qu = "select uid, type, value from addressbook where";
321 for (uint i = 0; i < m_uids.count(); i++ ) { 409 for (uint i = 0; i < m_uids.count(); i++ ) {
322 qu += " UID = " + QString::number( m_uids[i] ) + " OR"; 410 qu += " UID = " + QString::number( m_uids[i] ) + " OR";
323 } 411 }
324 qu.remove( qu.length()-2, 2 ); // Hmmmm.. 412 qu.remove( qu.length()-2, 2 ); // Hmmmm..
325 return qu; 413 return qu;
326 } 414 }
327 */ 415 */
416#ifdef __STORE_HORIZONTAL_
417 QString FindQuery::single()const{
418 QString qu = "select *";
419 qu += " from addressbook where uid = " + QString::number(m_uid);
420
421 // qWarning("find query: %s", qu.latin1() );
422 return qu;
423 }
424#else
328 QString FindQuery::single()const{ 425 QString FindQuery::single()const{
329 QString qu = "select uid, type, value from addressbook where uid = "; 426 QString qu = "select uid, type, value from addressbook where uid = ";
330 qu += QString::number(m_uid); 427 qu += QString::number(m_uid);
331 return qu; 428 return qu;
332 } 429 }
430#endif
333 431
334 432
335 FindCustomQuery::FindCustomQuery(int uid) 433 FindCustomQuery::FindCustomQuery(int uid)
336 : OSQLQuery(), m_uid( uid ) { 434 : OSQLQuery(), m_uid( uid ) {
337 } 435 }
338 FindCustomQuery::FindCustomQuery(const QArray<int>& ints) 436 FindCustomQuery::FindCustomQuery(const QArray<int>& ints)
339 : OSQLQuery(), m_uids( ints ){ 437 : OSQLQuery(), m_uids( ints ){
340 } 438 }
341 FindCustomQuery::~FindCustomQuery() { 439 FindCustomQuery::~FindCustomQuery() {
342 } 440 }
343 QString FindCustomQuery::query()const{ 441 QString FindCustomQuery::query()const{
344 // if ( m_uids.count() == 0 ) 442 // if ( m_uids.count() == 0 )
345 return single(); 443 return single();
346 } 444 }
347 QString FindCustomQuery::single()const{ 445 QString FindCustomQuery::single()const{
348 QString qu = "select uid, type, value from custom_data where uid = "; 446 QString qu = "select uid, type, value from custom_data where uid = ";
349 qu += QString::number(m_uid); 447 qu += QString::number(m_uid);
350 return qu; 448 return qu;
351 } 449 }
352 450
353}; 451};
354 452
355 453
356/* --------------------------------------------------------------------------- */ 454/* --------------------------------------------------------------------------- */
357 455
358OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */, 456OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */,
359 const QString& filename ): m_changed(false) 457 const QString& filename ): m_changed(false)
360{ 458{
361 qWarning("C'tor OContactAccessBackend_SQL starts"); 459 qWarning("C'tor OContactAccessBackend_SQL starts");
362 QTime t; 460 QTime t;
363 t.start(); 461 t.start();
364 462
365 /* Expecting to access the default filename if nothing else is set */ 463 /* Expecting to access the default filename if nothing else is set */
366 if ( filename.isEmpty() ){ 464 if ( filename.isEmpty() ){
367 m_fileName = Global::applicationFileName( "addressbook","addressbook.db" ); 465 m_fileName = Global::applicationFileName( "addressbook","addressbook.db" );
368 } else 466 } else
369 m_fileName = filename; 467 m_fileName = filename;
370 468
371 // Get the standart sql-driver from the OSQLManager.. 469 // Get the standart sql-driver from the OSQLManager..
372 OSQLManager man; 470 OSQLManager man;
373 m_driver = man.standard(); 471 m_driver = man.standard();
374 m_driver->setUrl( m_fileName ); 472 m_driver->setUrl( m_fileName );
375 473
376 load(); 474 load();
377 475
378 qWarning("C'tor OContactAccessBackend_SQL ends: %d", t.elapsed() ); 476 qWarning("C'tor OContactAccessBackend_SQL ends: %d ms", t.elapsed() );
379} 477}
380 478
381 479
382bool OContactAccessBackend_SQL::load () 480bool OContactAccessBackend_SQL::load ()
383{ 481{
384 if (!m_driver->open() ) 482 if (!m_driver->open() )
385 return false; 483 return false;
386 484
387 // Don't expect that the database exists. 485 // Don't expect that the database exists.
388 // It is save here to create the table, even if it 486 // It is save here to create the table, even if it
389 // do exist. ( Is that correct for all databases ?? ) 487 // do exist. ( Is that correct for all databases ?? )
390 CreateQuery creat; 488 CreateQuery creat;
391 OSQLResult res = m_driver->query( &creat ); 489 OSQLResult res = m_driver->query( &creat );
392 490
393 update(); 491 update();
394 492
395 return true; 493 return true;
396 494
397} 495}
398 496
399bool OContactAccessBackend_SQL::reload() 497bool OContactAccessBackend_SQL::reload()
400{ 498{
401 return load(); 499 return load();
402} 500}
@@ -457,146 +555,303 @@ bool OContactAccessBackend_SQL::remove ( int uid )
457 555
458 m_changed = true; 556 m_changed = true;
459 557
460 return true; 558 return true;
461} 559}
462 560
463bool OContactAccessBackend_SQL::replace ( const OContact &contact ) 561bool OContactAccessBackend_SQL::replace ( const OContact &contact )
464{ 562{
465 if ( !remove( contact.uid() ) ) 563 if ( !remove( contact.uid() ) )
466 return false; 564 return false;
467 565
468 return add( contact ); 566 return add( contact );
469} 567}
470 568
471 569
472OContact OContactAccessBackend_SQL::find ( int uid ) const 570OContact OContactAccessBackend_SQL::find ( int uid ) const
473{ 571{
474 qWarning("OContactAccessBackend_SQL::find()"); 572 qWarning("OContactAccessBackend_SQL::find()");
475 QTime t; 573 QTime t;
476 t.start(); 574 t.start();
477 575
478 OContact retContact( requestNonCustom( uid ) ); 576 OContact retContact( requestNonCustom( uid ) );
479 retContact.setExtraMap( requestCustom( uid ) ); 577 retContact.setExtraMap( requestCustom( uid ) );
480 578
481 qWarning("OContactAccessBackend_SQL::find() needed: %d", t.elapsed() ); 579 qWarning("OContactAccessBackend_SQL::find() needed: %d ms", t.elapsed() );
482 return retContact; 580 return retContact;
483} 581}
484 582
485 583
486 584
487QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ) 585QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() )
488{ 586{
489 QArray<int> nix(0); 587 QString qu = "SELECT uid FROM addressbook WHERE";
490 return nix; 588
589 QMap<int, QString> queryFields = query.toMap();
590 QStringList fieldList = OContactFields::untrfields( false );
591 QMap<QString, int> translate = OContactFields::untrFieldsToId();
592
593 // Convert every filled field to a SQL-Query
594 bool isAnyFieldSelected = false;
595 for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
596 int id = translate[*it];
597 QString queryStr = queryFields[id];
598 if ( !queryStr.isEmpty() ){
599 isAnyFieldSelected = true;
600 switch( id ){
601 default:
602 // Switching between case sensitive and insensitive...
603 // LIKE is not case sensitive, GLOB is case sensitive
604 // Do exist a better solution to switch this ?
605 if ( settings & OContactAccess::IgnoreCase )
606 qu += "(\"" + *it + "\"" + " LIKE " + "'"
607 + queryStr.replace(QRegExp("\\*"),"%") + "'" + ") AND ";
608 else
609 qu += "(\"" + *it + "\"" + " GLOB " + "'"
610 + queryStr + "'" + ") AND ";
611
612 }
613 }
614 }
615 // Skip trailing "AND"
616 if ( isAnyFieldSelected )
617 qu = qu.left( qu.length() - 4 );
618
619 qWarning( "queryByExample query: %s", qu.latin1() );
620
621 // Execute query and return the received uid's
622 OSQLRawQuery raw( qu );
623 OSQLResult res = m_driver->query( &raw );
624 if ( res.state() != OSQLResult::Success ){
625 QArray<int> empty;
626 return empty;
627 }
628
629 QArray<int> list = extractUids( res );
630
631 return list;
491} 632}
492 633
493QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const 634QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const
494{ 635{
495 QArray<int> nix(0); 636 QArray<int> nix(0);
496 return nix; 637 return nix;
497} 638}
498 639
499const uint OContactAccessBackend_SQL::querySettings() 640const uint OContactAccessBackend_SQL::querySettings()
500{ 641{
501 return 0; 642 return OContactAccess::IgnoreCase
643 || OContactAccess::WildCards;
502} 644}
503 645
504bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const 646bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const
505{ 647{
506 return false; 648 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
649 * may be added with any of the other settings. IgnoreCase should never used alone.
650 * Wildcards, RegExp, ExactMatch should never used at the same time...
651 */
652
653 // Step 1: Check whether the given settings are supported by this backend
654 if ( ( querySettings & (
655 OContactAccess::IgnoreCase
656 | OContactAccess::WildCards
657 // | OContactAccess::DateDiff
658 // | OContactAccess::DateYear
659 // | OContactAccess::DateMonth
660 // | OContactAccess::DateDay
661 // | OContactAccess::RegExp
662 // | OContactAccess::ExactMatch
663 ) ) != querySettings )
664 return false;
665
666 // Step 2: Check whether the given combinations are ok..
667
668 // IngoreCase alone is invalid
669 if ( querySettings == OContactAccess::IgnoreCase )
670 return false;
671
672 // WildCards, RegExp and ExactMatch should never used at the same time
673 switch ( querySettings & ~( OContactAccess::IgnoreCase
674 | OContactAccess::DateDiff
675 | OContactAccess::DateYear
676 | OContactAccess::DateMonth
677 | OContactAccess::DateDay
678 )
679 ){
680 case OContactAccess::RegExp:
681 return ( true );
682 case OContactAccess::WildCards:
683 return ( true );
684 case OContactAccess::ExactMatch:
685 return ( true );
686 case 0: // one of the upper removed bits were set..
687 return ( true );
688 default:
689 return ( false );
690 }
691
507} 692}
508 693
509QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int ) 694QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int )
510{ 695{
511 QTime t; 696 QTime t;
512 t.start(); 697 t.start();
513 698
514 // Not implemented.. 699#ifdef __STORE_HORIZONTAL_
700 QString query = "SELECT uid FROM addressbook ";
701 query += "ORDER BY \"Last Name\" ";
702#else
515 QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' "; 703 QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' ";
704 query += "ORDER BY upper( value )";
705#endif
516 706
517 query += "ORDER BY value ";
518 if ( !asc ) 707 if ( !asc )
519 query += "DESC"; 708 query += "DESC";
520 709
521 qWarning("sorted query is: %s", query.latin1() ); 710 // qWarning("sorted query is: %s", query.latin1() );
522 711
523 OSQLRawQuery raw( query ); 712 OSQLRawQuery raw( query );
524 OSQLResult res = m_driver->query( &raw ); 713 OSQLResult res = m_driver->query( &raw );
525 if ( res.state() != OSQLResult::Success ){ 714 if ( res.state() != OSQLResult::Success ){
526 QArray<int> empty; 715 QArray<int> empty;
527 return empty; 716 return empty;
528 } 717 }
529 718
530 QArray<int> list = extractUids( res ); 719 QArray<int> list = extractUids( res );
531 720
532 qWarning("sorted needed %d ms!", t.elapsed() ); 721 qWarning("sorted needed %d ms!", t.elapsed() );
533 return list; 722 return list;
534} 723}
535 724
536 725
537void OContactAccessBackend_SQL::update() 726void OContactAccessBackend_SQL::update()
538{ 727{
539 qWarning("Update starts"); 728 qWarning("Update starts");
540 QTime t; 729 QTime t;
541 t.start(); 730 t.start();
542 731
543 // Now load the database set and extract the uid's 732 // Now load the database set and extract the uid's
544 // which will be held locally 733 // which will be held locally
545 734
546 LoadQuery lo; 735 LoadQuery lo;
547 OSQLResult res = m_driver->query(&lo); 736 OSQLResult res = m_driver->query(&lo);
548 if ( res.state() != OSQLResult::Success ) 737 if ( res.state() != OSQLResult::Success )
549 return; 738 return;
550 739
551 m_uids = extractUids( res ); 740 m_uids = extractUids( res );
552 741
553 m_changed = false; 742 m_changed = false;
554 743
555 qWarning("Update ends %d", t.elapsed() ); 744 qWarning("Update ends %d ms", t.elapsed() );
556} 745}
557 746
558QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const 747QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const
559{ 748{
560 qWarning("extractUids"); 749 qWarning("extractUids");
561 QTime t; 750 QTime t;
562 t.start(); 751 t.start();
563 OSQLResultItem::ValueList list = res.results(); 752 OSQLResultItem::ValueList list = res.results();
564 OSQLResultItem::ValueList::Iterator it; 753 OSQLResultItem::ValueList::Iterator it;
565 QArray<int> ints(list.count() ); 754 QArray<int> ints(list.count() );
566 qWarning(" count = %d", list.count() ); 755 qWarning(" count = %d", list.count() );
567 756
568 int i = 0; 757 int i = 0;
569 for (it = list.begin(); it != list.end(); ++it ) { 758 for (it = list.begin(); it != list.end(); ++it ) {
570 ints[i] = (*it).data("uid").toInt(); 759 ints[i] = (*it).data("uid").toInt();
571 i++; 760 i++;
572 } 761 }
573 qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() ); 762 qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() );
574 763
575 return ints; 764 return ints;
576 765
577} 766}
578 767
768#ifdef __STORE_HORIZONTAL_
769QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const
770{
771 QTime t;
772 t.start();
773
774 QMap<int, QString> nonCustomMap;
775
776 int t2needed = 0;
777 int t3needed = 0;
778 QTime t2;
779 t2.start();
780 FindQuery query( uid );
781 OSQLResult res_noncustom = m_driver->query( &query );
782 t2needed = t2.elapsed();
783
784 OSQLResultItem resItem = res_noncustom.first();
785
786 QTime t3;
787 t3.start();
788 // Now loop through all columns
789 QStringList fieldList = OContactFields::untrfields( false );
790 QMap<QString, int> translate = OContactFields::untrFieldsToId();
791 for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
792 // Get data for the selected column and store it with the
793 // corresponding id into the map..
794
795 int id = translate[*it];
796 QString value = resItem.data( (*it) );
797
798 // qWarning("Reading %s... found: %s", (*it).latin1(), value.latin1() );
799
800 switch( id ){
801 case Qtopia::Birthday:
802 case Qtopia::Anniversary:{
803 // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
804 QStringList list = QStringList::split( '-', value );
805 QStringList::Iterator lit = list.begin();
806 int year = (*lit).toInt();
807 int month = (*(++lit)).toInt();
808 int day = (*(++lit)).toInt();
809 if ( ( day != 0 ) && ( month != 0 ) && ( year != 0 ) ){
810 QDate date( year, month, day );
811 nonCustomMap.insert( id, OConversion::dateToString( date ) );
812 }
813 }
814 break;
815 case Qtopia::AddressCategory:
816 qWarning("Category is: %s", value.latin1() );
817 default:
818 nonCustomMap.insert( id, value );
819 }
820 }
821
822 // First insert uid
823 nonCustomMap.insert( Qtopia::AddressUid, resItem.data( "uid" ) );
824 t3needed = t3.elapsed();
825
826 // qWarning("Adding UID: %s", resItem.data( "uid" ).latin1() );
827 qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms",
828 t.elapsed(), t2needed, t3needed );
829
830 return nonCustomMap;
831}
832#else
833
579QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const 834QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const
580{ 835{
581 QTime t; 836 QTime t;
582 t.start(); 837 t.start();
583 838
584 QMap<int, QString> nonCustomMap; 839 QMap<int, QString> nonCustomMap;
585 840
586 int t2needed = 0; 841 int t2needed = 0;
587 QTime t2; 842 QTime t2;
588 t2.start(); 843 t2.start();
589 FindQuery query( uid ); 844 FindQuery query( uid );
590 OSQLResult res_noncustom = m_driver->query( &query ); 845 OSQLResult res_noncustom = m_driver->query( &query );
591 t2needed = t2.elapsed(); 846 t2needed = t2.elapsed();
592 847
593 if ( res_noncustom.state() == OSQLResult::Failure ) { 848 if ( res_noncustom.state() == OSQLResult::Failure ) {
594 qWarning("OSQLResult::Failure in find query !!"); 849 qWarning("OSQLResult::Failure in find query !!");
595 QMap<int, QString> empty; 850 QMap<int, QString> empty;
596 return empty; 851 return empty;
597 } 852 }
598 853
599 int t3needed = 0; 854 int t3needed = 0;
600 QTime t3; 855 QTime t3;
601 t3.start(); 856 t3.start();
602 QMap<QString, int> translateMap = OContactFields::untrFieldsToId(); 857 QMap<QString, int> translateMap = OContactFields::untrFieldsToId();
@@ -612,53 +867,55 @@ QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const
612 // Birthday and Anniversary are encoded special ( yyyy-mm-dd ) 867 // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
613 QStringList list = QStringList::split( '-', (*it).data( "value" ) ); 868 QStringList list = QStringList::split( '-', (*it).data( "value" ) );
614 QStringList::Iterator lit = list.begin(); 869 QStringList::Iterator lit = list.begin();
615 int year = (*lit).toInt(); 870 int year = (*lit).toInt();
616 qWarning("1. %s", (*lit).latin1()); 871 qWarning("1. %s", (*lit).latin1());
617 int month = (*(++lit)).toInt(); 872 int month = (*(++lit)).toInt();
618 qWarning("2. %s", (*lit).latin1()); 873 qWarning("2. %s", (*lit).latin1());
619 int day = (*(++lit)).toInt(); 874 int day = (*(++lit)).toInt();
620 qWarning("3. %s", (*lit).latin1()); 875 qWarning("3. %s", (*lit).latin1());
621 qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day ); 876 qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day );
622 QDate date( year, month, day ); 877 QDate date( year, month, day );
623 nonCustomMap.insert( typeId, OConversion::dateToString( date ) ); 878 nonCustomMap.insert( typeId, OConversion::dateToString( date ) );
624 } 879 }
625 break; 880 break;
626 default: 881 default:
627 nonCustomMap.insert( typeId, 882 nonCustomMap.insert( typeId,
628 (*it).data( "value" ) ); 883 (*it).data( "value" ) );
629 } 884 }
630 } 885 }
631 } 886 }
632 // Add UID to Map.. 887 // Add UID to Map..
633 nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) ); 888 nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) );
634 t3needed = t3.elapsed(); 889 t3needed = t3.elapsed();
635 890
636 qWarning("RequestNonCustom needed: ins:%d, query: %d, mapping: %d", t.elapsed(), t2needed, t3needed ); 891 qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", t.elapsed(), t2needed, t3needed );
637 return nonCustomMap; 892 return nonCustomMap;
638} 893}
639 894
895#endif // __STORE_HORIZONTAL_
896
640QMap<QString, QString> OContactAccessBackend_SQL::requestCustom( int uid ) const 897QMap<QString, QString> OContactAccessBackend_SQL::requestCustom( int uid ) const
641{ 898{
642 QTime t; 899 QTime t;
643 t.start(); 900 t.start();
644 901
645 QMap<QString, QString> customMap; 902 QMap<QString, QString> customMap;
646 903
647 FindCustomQuery query( uid ); 904 FindCustomQuery query( uid );
648 OSQLResult res_custom = m_driver->query( &query ); 905 OSQLResult res_custom = m_driver->query( &query );
649 906
650 if ( res_custom.state() == OSQLResult::Failure ) { 907 if ( res_custom.state() == OSQLResult::Failure ) {
651 qWarning("OSQLResult::Failure in find query !!"); 908 qWarning("OSQLResult::Failure in find query !!");
652 QMap<QString, QString> empty; 909 QMap<QString, QString> empty;
653 return empty; 910 return empty;
654 } 911 }
655 912
656 OSQLResultItem::ValueList list = res_custom.results(); 913 OSQLResultItem::ValueList list = res_custom.results();
657 OSQLResultItem::ValueList::Iterator it = list.begin(); 914 OSQLResultItem::ValueList::Iterator it = list.begin();
658 for ( ; it != list.end(); ++it ) { 915 for ( ; it != list.end(); ++it ) {
659 customMap.insert( (*it).data( "type" ), (*it).data( "value" ) ); 916 customMap.insert( (*it).data( "type" ), (*it).data( "value" ) );
660 } 917 }
661 918
662 qWarning("RequestCustom needed: %d", t.elapsed() ); 919 qWarning("RequestCustom needed: %d ms", t.elapsed() );
663 return customMap; 920 return customMap;
664} 921}