|
1 /* |
|
2 * Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Adaptation layer to SQLite database* |
|
15 */ |
|
16 |
|
17 // INCLUDE FILES |
|
18 #include "mdssqliteconnection.h" |
|
19 #include "mdslogger.h" |
|
20 |
|
21 __USES_LOGGER |
|
22 |
|
23 CMdSSqLiteConnection* CMdSSqLiteConnection::NewL() |
|
24 { |
|
25 CMdSSqLiteConnection* self = CMdSSqLiteConnection::NewLC(); |
|
26 CleanupStack::Pop( self ); |
|
27 return self; |
|
28 } |
|
29 |
|
30 |
|
31 CMdSSqLiteConnection* CMdSSqLiteConnection::NewLC() |
|
32 { |
|
33 CMdSSqLiteConnection* self = new ( ELeave ) CMdSSqLiteConnection( ); |
|
34 CleanupStack::PushL( self ); |
|
35 self->ConstructL( ); |
|
36 return self; |
|
37 } |
|
38 |
|
39 |
|
40 CMdSSqLiteConnection::CMdSSqLiteConnection() |
|
41 : iDbFileName( NULL ), iEnableTransaction( ETrue ),iNotFinishFindQuery( NULL ) |
|
42 { |
|
43 } |
|
44 |
|
45 |
|
46 CMdSSqLiteConnection::~CMdSSqLiteConnection() |
|
47 { |
|
48 CloseDb(); |
|
49 |
|
50 delete iDbFileName; |
|
51 |
|
52 iNotFinishFindQuery = NULL; |
|
53 } |
|
54 |
|
55 void CMdSSqLiteConnection::DeleteDb( TDesC16* aName ) |
|
56 { |
|
57 if( aName ) |
|
58 { |
|
59 RSqlDatabase::Delete( *aName ); |
|
60 } |
|
61 else |
|
62 { |
|
63 RSqlDatabase::Delete( KMdsSqlDbDefaultName ); |
|
64 } |
|
65 } |
|
66 |
|
67 void CMdSSqLiteConnection::CloseDb() |
|
68 { |
|
69 iMdeSqlDb.Close(); |
|
70 } |
|
71 |
|
72 void CMdSSqLiteConnection::ConstructL() |
|
73 { |
|
74 } |
|
75 |
|
76 void CMdSSqLiteConnection::OpenDbL( const TDesC& aDbFileName ) |
|
77 { |
|
78 _LIT8( KMdsSqlDbaConfig, "cache_size=10000; page_size=4096; encoding=\"UTF-16\";"); |
|
79 |
|
80 TInt err = KErrNone; |
|
81 |
|
82 delete iDbFileName; |
|
83 iDbFileName = NULL; // in case AllocL leaves |
|
84 iDbFileName = aDbFileName.AllocL(); |
|
85 |
|
86 // we need to set up policy, because we use secure database |
|
87 TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysPass); |
|
88 RSqlSecurityPolicy sqlSecurityPolicy; |
|
89 CleanupClosePushL( sqlSecurityPolicy ); |
|
90 err = sqlSecurityPolicy.Create( defaultPolicy ); |
|
91 |
|
92 if ( err != KErrNone ) |
|
93 { |
|
94 _LIT( KMdsSecurityCheckFail, "Security check fail" ); |
|
95 TraceAndLeaveL( KMdsSecurityCheckFail, err ); |
|
96 } |
|
97 /** |
|
98 * Open database: |
|
99 * First we try to create new db. If this fails check if db already exists and |
|
100 * try to open it. Otherwise we cannot open it and we leave |
|
101 */ |
|
102 err = iMdeSqlDb.Create( *iDbFileName, sqlSecurityPolicy, &KMdsSqlDbaConfig ); |
|
103 if ( err != KErrNone ) |
|
104 { |
|
105 // it could fail because database exists |
|
106 if ( err == KErrAlreadyExists ) |
|
107 { |
|
108 err = iMdeSqlDb.Open( *iDbFileName, &KMdsSqlDbaConfig ); |
|
109 if ( err != KErrNone ) |
|
110 { |
|
111 __LOG1( ELogDb, "Cannot open database %d", err ); |
|
112 } |
|
113 } |
|
114 else |
|
115 { |
|
116 __LOG1( ELogDb, "Unknown error while creating %d", err ); |
|
117 } |
|
118 |
|
119 User::LeaveIfError( err ); |
|
120 } |
|
121 CleanupStack::PopAndDestroy( &sqlSecurityPolicy ); |
|
122 } |
|
123 |
|
124 TInt CMdSSqLiteConnection::ExecuteL( const TDesC& aCommand, |
|
125 const RRowData& aVariables, |
|
126 RMdsStatement* aStatement ) |
|
127 { |
|
128 TInt err = KErrNone; |
|
129 |
|
130 if ( aVariables.Size() == 0 ) |
|
131 { |
|
132 // no variables |
|
133 err = iMdeSqlDb.Exec( aCommand ); |
|
134 |
|
135 if ( err < KErrNone ) |
|
136 { |
|
137 _LIT( KMdSExec, "Exec (no variables)" ); |
|
138 TraceAndLeaveL( KMdSExec, err ); |
|
139 } |
|
140 } |
|
141 else if ( aStatement ) |
|
142 { |
|
143 if ( aStatement->iPrepared == EFalse ) |
|
144 { |
|
145 err = aStatement->iStatement.Prepare( iMdeSqlDb, aCommand ); |
|
146 |
|
147 if ( err < KErrNone ) |
|
148 { |
|
149 _LIT( KMdSPrepare, "Prepare" ); |
|
150 TraceAndLeaveL( KMdSPrepare, err ); |
|
151 } |
|
152 aStatement->iPrepared = ETrue; |
|
153 } |
|
154 else |
|
155 { |
|
156 err = aStatement->iStatement.Reset(); |
|
157 if ( err < KErrNone ) |
|
158 { |
|
159 _LIT( KMdSResume, "Resume" ); |
|
160 TraceAndLeaveL( KMdSResume, err ); |
|
161 } |
|
162 } |
|
163 |
|
164 DoBindL( aStatement->iStatement, aVariables ); |
|
165 err = aStatement->iStatement.Exec(); |
|
166 |
|
167 if ( err < KErrNone ) |
|
168 { |
|
169 aStatement->iStatement.Reset(); |
|
170 aStatement->iPrepared = EFalse; |
|
171 _LIT( KMdSExec, "Exec" ); |
|
172 TraceAndLeaveL( KMdSExec, err ); |
|
173 } |
|
174 } |
|
175 else |
|
176 { |
|
177 RSqlStatement mdeSqlDbStmt; |
|
178 CleanupClosePushL( mdeSqlDbStmt ); |
|
179 err = mdeSqlDbStmt.Prepare( iMdeSqlDb, aCommand ); |
|
180 |
|
181 if ( err < KErrNone ) |
|
182 { |
|
183 _LIT( KMdsPrepare, "Prepare (no statement)" ); |
|
184 TraceAndLeaveL( KMdsPrepare, err ); |
|
185 } |
|
186 |
|
187 DoBindL( mdeSqlDbStmt, aVariables ); |
|
188 |
|
189 err = mdeSqlDbStmt.Exec(); |
|
190 |
|
191 if ( err < KErrNone ) |
|
192 { |
|
193 _LIT( KMdsExec, "Exec (no statement)" ); |
|
194 TraceAndLeaveL( KMdsExec, err ); |
|
195 } |
|
196 |
|
197 CleanupStack::PopAndDestroy( &mdeSqlDbStmt ); |
|
198 } |
|
199 return err; |
|
200 } |
|
201 |
|
202 void CMdSSqLiteConnection::ExecuteQueryL( const TDesC& aQuery, |
|
203 RMdsStatement& aStatement, |
|
204 const RRowData& aVariables ) |
|
205 { |
|
206 TInt stmterr; |
|
207 if ( aStatement.iPrepared == EFalse ) |
|
208 { |
|
209 stmterr = aStatement.iStatement.Prepare( iMdeSqlDb, aQuery ); |
|
210 if ( stmterr != KErrNone ) |
|
211 { |
|
212 _LIT( KMdSQueryPrepare, "Query Prepare" ); |
|
213 TraceAndLeaveL( KMdSQueryPrepare, stmterr ); |
|
214 } |
|
215 aStatement.iPrepared = ETrue; |
|
216 } |
|
217 else |
|
218 { |
|
219 stmterr = aStatement.iStatement.Reset(); |
|
220 if ( stmterr != KErrNone ) |
|
221 { |
|
222 _LIT( KMdSQueryReset, "Query Reset" ); |
|
223 TraceAndLeaveL( KMdSQueryReset, stmterr ); |
|
224 } |
|
225 } |
|
226 |
|
227 DoBindL( aStatement.iStatement, aVariables ); |
|
228 } |
|
229 |
|
230 void CMdSSqLiteConnection::DoBindL( RSqlStatement& aStatement, const RRowData& aVariables ) |
|
231 { |
|
232 const TInt count( aVariables.Size() ); |
|
233 for( TInt i=0; i < count; ++i ) |
|
234 { |
|
235 switch ( aVariables.Column( i ).Type() ) |
|
236 { |
|
237 case EColumnInt32: |
|
238 { |
|
239 TInt32 val = 0; |
|
240 aVariables.Column( i ).Get( val ); |
|
241 aStatement.BindInt( i, val ); |
|
242 break; |
|
243 } |
|
244 case EColumnUint32: |
|
245 { |
|
246 TUint32 val = 0; |
|
247 aVariables.Column( i ).Get( val ); |
|
248 aStatement.BindInt64( i, (TInt64)val ); |
|
249 break; |
|
250 } |
|
251 case EColumnBool: |
|
252 { |
|
253 TBool val = 0; |
|
254 aVariables.Column( i ).Get( val ); |
|
255 aStatement.BindInt( i, val ); |
|
256 break; |
|
257 } |
|
258 case EColumnInt64: |
|
259 { |
|
260 TInt64 val = 0; |
|
261 aVariables.Column( i ).Get( val ); |
|
262 aStatement.BindInt64( i, val ); |
|
263 break; |
|
264 } |
|
265 case EColumnReal32: |
|
266 { |
|
267 TReal32 val = 0; |
|
268 aVariables.Column( i ).Get( val ); |
|
269 aStatement.BindReal( i, val ); |
|
270 break; |
|
271 } |
|
272 case EColumnReal64: |
|
273 { |
|
274 TReal64 val = 0; |
|
275 aVariables.Column( i ).Get( val ); |
|
276 aStatement.BindReal( i, val ); |
|
277 break; |
|
278 } |
|
279 case EColumnTime: |
|
280 { |
|
281 TTime val = TInt64(0); |
|
282 aVariables.Column( i ).Get( val ); |
|
283 aStatement.BindInt64( i, val.Int64() ); |
|
284 break; |
|
285 } |
|
286 case EColumnDes16: |
|
287 { |
|
288 TPtrC16 val = TPtr16((TUint16*)0, 0); //KNullPtr16; |
|
289 aVariables.Column( i ).Get( val ); |
|
290 aStatement.BindText( i, val ); |
|
291 break; |
|
292 } |
|
293 case EColumnNotUsed: |
|
294 // skip this variable |
|
295 break; |
|
296 default: |
|
297 #ifdef _DEBUG |
|
298 User::Panic( _L( "MdSSCDoB" ), KErrCorrupt ); |
|
299 #endif |
|
300 User::Leave( KErrCorrupt ); |
|
301 } |
|
302 } |
|
303 } |
|
304 |
|
305 TBool CMdSSqLiteConnection::NextRowL( RMdsStatement& aQuery, RRowData& aRow ) |
|
306 { |
|
307 const TInt qerr = aQuery.iStatement.Next(); |
|
308 if ( qerr == KSqlAtEnd ) |
|
309 { |
|
310 return EFalse; |
|
311 } |
|
312 else if ( qerr != KSqlAtRow ) |
|
313 { |
|
314 _LIT( KMdsQueryNextRow, "Query NextRow" ); |
|
315 TraceAndLeaveL( KMdsQueryNextRow, qerr ); |
|
316 } |
|
317 |
|
318 // obtain column data into local storage and row data pointer |
|
319 ColumnsL( aQuery.iStatement, aRow ); |
|
320 |
|
321 return ETrue; |
|
322 } |
|
323 |
|
324 void CMdSSqLiteConnection::CurrentRowL( const RMdsStatement& aQuery, RRowData& aRow ) |
|
325 { |
|
326 // obtain column data into local storage and row data pointer |
|
327 if ( EFalse != aQuery.iStatement.AtRow() ) |
|
328 { |
|
329 ColumnsL( aQuery.iStatement, aRow ); |
|
330 } |
|
331 else |
|
332 { |
|
333 _LIT( KMdsNoProcessableRow, "Wrong row to process" ); |
|
334 TraceAndLeaveL( KMdsNoProcessableRow, KSqlErrNotFound ); |
|
335 } |
|
336 } |
|
337 |
|
338 void CMdSSqLiteConnection::ColumnsL( const RSqlStatement& aStatement, RRowData& aRow ) |
|
339 { |
|
340 const TInt count( aRow.Size() ); |
|
341 for( TInt i=0; i < count; ++i ) |
|
342 { |
|
343 // get data in column, check for type |
|
344 const TSqlColumnType actual = aStatement.ColumnType( i ); |
|
345 |
|
346 if( actual == ESqlNull ) |
|
347 { |
|
348 aRow.Column( i ).Set( (const HBufC16*)NULL ); |
|
349 |
|
350 continue; |
|
351 } |
|
352 |
|
353 const TColumnDataType coltype = aRow.Column( i ).Type(); |
|
354 switch ( coltype ) |
|
355 { |
|
356 case EColumnBool: |
|
357 { |
|
358 TInt valInt = aStatement.ColumnInt( i ); |
|
359 const TBool valBool = valInt ? ETrue : EFalse; |
|
360 aRow.Column( i ).Set( valBool ); |
|
361 break; |
|
362 } |
|
363 case EColumnInt32: |
|
364 { |
|
365 TInt32 valInt = aStatement.ColumnInt( i ); |
|
366 aRow.Column( i ).Set( valInt ); |
|
367 break; |
|
368 } |
|
369 case EColumnUint32: |
|
370 { |
|
371 TInt64 valInt64 = aStatement.ColumnInt64( i ); |
|
372 aRow.Column( i ).Set( (TUint32)valInt64 ); |
|
373 break; |
|
374 } |
|
375 case EColumnInt64: |
|
376 { |
|
377 TInt64 valInt64 = aStatement.ColumnInt64( i ); |
|
378 aRow.Column( i ).Set( valInt64 ); |
|
379 break; |
|
380 } |
|
381 case EColumnReal32: |
|
382 { |
|
383 TReal valReal = aStatement.ColumnReal( i ); |
|
384 aRow.Column( i ).Set( static_cast<TReal32>( valReal ) ); |
|
385 break; |
|
386 } |
|
387 case EColumnReal64: |
|
388 { |
|
389 TReal valReal = aStatement.ColumnReal( i ); |
|
390 aRow.Column( i ).Set( valReal ); |
|
391 break; |
|
392 } |
|
393 case EColumnTime: |
|
394 { |
|
395 TTime valTime = aStatement.ColumnInt64( i ); |
|
396 aRow.Column( i ).Set( valTime ); |
|
397 break; |
|
398 } |
|
399 case EColumnDes16: |
|
400 { |
|
401 switch ( actual ) |
|
402 { |
|
403 case ESqlText: |
|
404 { |
|
405 TPtrC16 valTPtrC16 = aStatement.ColumnTextL( i ); |
|
406 HBufC16* valHBuf16 = HBufC16::NewL( valTPtrC16.Length() ); |
|
407 *valHBuf16 = valTPtrC16; |
|
408 aRow.Column( i ).Set( valHBuf16 ); |
|
409 break; |
|
410 } |
|
411 case ESqlInt: |
|
412 { |
|
413 HBufC16* valHBuf16int32 = HBufC16::NewL( 30 ); |
|
414 TInt valInt = aStatement.ColumnInt( i ); |
|
415 valHBuf16int32->Des().Num( valInt ); |
|
416 aRow.Column( i ).Set( valHBuf16int32 ); |
|
417 break; |
|
418 } |
|
419 case ESqlInt64: |
|
420 { |
|
421 HBufC16* valHBuf16int64 = HBufC16::NewL( 30 ); |
|
422 TInt64 valInt64 = aStatement.ColumnInt64( i ); |
|
423 valHBuf16int64->Des().Num( valInt64 ); |
|
424 aRow.Column( i ).Set( valHBuf16int64 ); |
|
425 break; |
|
426 } |
|
427 case ESqlReal: |
|
428 { |
|
429 HBufC16* valHBuf16real64 = HBufC16::NewL( 40 ); |
|
430 TReal valReal = aStatement.ColumnReal( i ); |
|
431 TRealFormat realFormat; |
|
432 realFormat.iType |= KAllowThreeDigitExp; |
|
433 valHBuf16real64->Des().Num( valReal, realFormat ); |
|
434 aRow.Column( i ).Set( valHBuf16real64 ); |
|
435 break; |
|
436 } |
|
437 case ESqlNull: |
|
438 { |
|
439 aRow.Column( i ).Set( (HBufC16*)NULL ); |
|
440 break; |
|
441 } |
|
442 default: |
|
443 { |
|
444 #ifdef _DEBUG |
|
445 User::Panic( _L( "MdSSCCo1" ), KErrCorrupt ); |
|
446 #endif |
|
447 User::Leave( KErrCorrupt ); |
|
448 } |
|
449 } |
|
450 |
|
451 break; |
|
452 } |
|
453 case EColumnNotUsed: |
|
454 // skip this round |
|
455 break; |
|
456 |
|
457 default: |
|
458 #ifdef _DEBUG |
|
459 User::Panic( _L( "MdSSCCo2" ), KErrCorrupt ); |
|
460 #endif |
|
461 User::Leave( KErrCorrupt ); |
|
462 } |
|
463 } |
|
464 } |
|
465 |
|
466 void CMdSSqLiteConnection::Terminate( RMdsStatement& aQuery ) |
|
467 { |
|
468 aQuery.Close(); |
|
469 EnableTransaction( ETrue, aQuery ); |
|
470 } |
|
471 |
|
472 void CMdSSqLiteConnection::TransactionBeginL() |
|
473 { |
|
474 if ( !iEnableTransaction || iMdeSqlDb.InTransaction() ) |
|
475 { |
|
476 return; |
|
477 } |
|
478 iEnableTransaction = EFalse; |
|
479 iTransactionOngoing = ETrue; |
|
480 _LIT(KBeginTransaction, "BEGIN;"); |
|
481 RRowData emptyRow; |
|
482 CleanupClosePushL( emptyRow ); |
|
483 TRAPD( err, ExecuteL(KBeginTransaction, emptyRow) ); |
|
484 if (err != KErrNone) |
|
485 { |
|
486 _LIT( KMdsTransactionBegin, "Transaction begin error" ); |
|
487 TraceAndLeaveL( KMdsTransactionBegin, err ); |
|
488 } |
|
489 CleanupStack::PopAndDestroy( &emptyRow ); |
|
490 } |
|
491 |
|
492 void CMdSSqLiteConnection::TransactionCommitL() |
|
493 { |
|
494 if ( !iTransactionOngoing ) |
|
495 { |
|
496 return; |
|
497 } |
|
498 _LIT(KCommit, "COMMIT;"); |
|
499 RRowData emptyRow; |
|
500 CleanupClosePushL( emptyRow ); |
|
501 TRAPD( err, ExecuteL(KCommit, emptyRow) ); |
|
502 if (err != KErrNone) |
|
503 { |
|
504 _LIT( KMdsTransactionCommit, "Transaction commit error" ); |
|
505 TraceAndLeaveL( KMdsTransactionCommit, err ); |
|
506 } |
|
507 if( !iNotFinishFindQuery ) |
|
508 { |
|
509 iEnableTransaction = ETrue; |
|
510 } |
|
511 iTransactionOngoing = EFalse; |
|
512 CleanupStack::PopAndDestroy( &emptyRow ); |
|
513 } |
|
514 |
|
515 void CMdSSqLiteConnection::TransactionRollbackL() |
|
516 { |
|
517 if ( !iTransactionOngoing ) |
|
518 { |
|
519 return; |
|
520 } |
|
521 _LIT(KRollback, "ROLLBACK;"); |
|
522 RRowData emptyRow; |
|
523 CleanupClosePushL( emptyRow ); |
|
524 TRAPD( err, ExecuteL(KRollback, emptyRow) ); |
|
525 if( !iNotFinishFindQuery ) |
|
526 { |
|
527 iEnableTransaction = ETrue; |
|
528 } |
|
529 iTransactionOngoing = EFalse; |
|
530 if (err != KErrNone) |
|
531 { |
|
532 _LIT( KMdsTransactionRollback, "Transaction rollback error" ); |
|
533 TraceAndLeaveL( KMdsTransactionRollback, err ); |
|
534 } |
|
535 CleanupStack::PopAndDestroy( &emptyRow ); |
|
536 } |
|
537 |
|
538 #ifdef _DEBUG |
|
539 void CMdSSqLiteConnection::TraceAndLeaveL( const TDesC& aFailedCommand, TInt aSqliteError ) |
|
540 { |
|
541 TPtrC errorMsg = iMdeSqlDb.LastErrorMessage(); |
|
542 if ( aFailedCommand.Length() > 0 ) |
|
543 { |
|
544 __LOG2( ELogDb, "%S %d", &aFailedCommand, aSqliteError ); |
|
545 } |
|
546 __LOG1( ELogDb, "SQLiteError description: %S", &errorMsg ); |
|
547 User::Leave( aSqliteError ); |
|
548 } |
|
549 #else |
|
550 void CMdSSqLiteConnection::TraceAndLeaveL( const TDesC& /*aFailedCommand*/, TInt aSqliteError ) |
|
551 { |
|
552 User::Leave( aSqliteError ); |
|
553 } |
|
554 #endif |
|
555 |
|
556 const TDesC& CMdSSqLiteConnection::DbFileName() const |
|
557 { |
|
558 return *iDbFileName; |
|
559 } |
|
560 |
|
561 void CMdSSqLiteConnection::EnableTransaction( TBool aEnable, RMdsStatement& aQuery ) |
|
562 { |
|
563 if( aEnable ) |
|
564 { |
|
565 // check whether current query is the query which disabled the transaction when enabling transaction |
|
566 if( !iEnableTransaction && ( iNotFinishFindQuery == &aQuery ) ) |
|
567 { |
|
568 if( !iTransactionOngoing ) |
|
569 { |
|
570 iEnableTransaction = aEnable; |
|
571 } |
|
572 iNotFinishFindQuery = NULL; |
|
573 } |
|
574 } |
|
575 else |
|
576 { |
|
577 iEnableTransaction = aEnable; |
|
578 // save current find operation which will continue when diable transaction |
|
579 iNotFinishFindQuery = &aQuery; |
|
580 } |
|
581 } |
|
582 |