|
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include "US_STD.H" |
|
17 |
|
18 // Class CDbStoreDatabase::CCompactor |
|
19 |
|
20 NONSHARABLE_CLASS(CDbStoreDatabase::CCompactor) : public CDbStoreDatabase::CStepper |
|
21 { |
|
22 public: |
|
23 static CCompactor* NewL(CDbDatabase::TUtility aType, CStreamStore& aStore, |
|
24 TInt& aReclaim, TInt& aStep); |
|
25 ~CCompactor(); |
|
26 private: |
|
27 inline CCompactor(TInt& aReclaim); |
|
28 // from CStepper |
|
29 TInt StepL(TInt aStep); |
|
30 private: |
|
31 RStoreReclaim iReclaimer; |
|
32 TInt& iReclaim; |
|
33 }; |
|
34 |
|
35 inline CDbStoreDatabase::CCompactor::CCompactor(TInt& aReclaim) |
|
36 :iReclaim(aReclaim) |
|
37 { |
|
38 } |
|
39 |
|
40 CDbStoreDatabase::CCompactor* CDbStoreDatabase::CCompactor::NewL(CDbDatabase::TUtility aType, |
|
41 CStreamStore& aStore, |
|
42 TInt& aReclaim,TInt& aStep) |
|
43 { |
|
44 CCompactor* self=new(ELeave) CCompactor(aReclaim); |
|
45 CleanupStack::PushL(self); |
|
46 if (aType==CDbDatabase::ECompact) |
|
47 self->iReclaimer.CompactL(aStore,aStep); |
|
48 else |
|
49 self->iReclaimer.OpenL(aStore,aStep); |
|
50 CleanupStack::Pop(); |
|
51 return self; |
|
52 } |
|
53 |
|
54 CDbStoreDatabase::CCompactor::~CCompactor() |
|
55 { |
|
56 iReclaimer.Close(); |
|
57 } |
|
58 |
|
59 // |
|
60 // Single step the compactor |
|
61 // We cannot deal with the "in use" scenario as we could end up locking out forever |
|
62 // that has to be left to clients using the RDbIncremental interface |
|
63 // |
|
64 TInt CDbStoreDatabase::CCompactor::StepL(TInt aStep) |
|
65 { |
|
66 iReclaimer.NextL(aStep); |
|
67 if (aStep==0) |
|
68 { |
|
69 iReclaim=iReclaimer.Available(); |
|
70 iReclaimer.Close(); |
|
71 } |
|
72 return aStep; |
|
73 } |
|
74 |
|
75 |
|
76 // Class CDbStoreDatabase |
|
77 |
|
78 EXPORT_C CDbStoreDatabase::CDbStoreDatabase() |
|
79 :iReclaim(KErrGeneral) |
|
80 { |
|
81 } |
|
82 |
|
83 // |
|
84 // Create a StoreDatabase object. This type shares the store |
|
85 // |
|
86 CDbStoreDatabase* CDbStoreDatabase::NewLC(CStreamStore* aStore) |
|
87 { |
|
88 __ASSERT(aStore); |
|
89 CDbStoreDatabase* self=new(ELeave) CDbStoreDatabase; |
|
90 CleanupStack::PushL(self); |
|
91 self->iStore=aStore; |
|
92 self->iSharedStore=1; |
|
93 return self; |
|
94 } |
|
95 |
|
96 |
|
97 //SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method. |
|
98 CDbDatabase* CDbStoreDatabase::CreateL(CStreamStore* aStore,TStreamId& aStreamId) |
|
99 { |
|
100 CDbStoreDatabase* self=NewLC(aStore); |
|
101 aStreamId=self->ConstructL(); |
|
102 CDbDatabase* db=self->InterfaceL(); |
|
103 CleanupStack::Pop(); // self |
|
104 return db; |
|
105 } |
|
106 |
|
107 // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method. |
|
108 // Phase 2 construction for creating a new database |
|
109 // Initialise a new database object, creating the required persistent structure |
|
110 // |
|
111 EXPORT_C TStreamId CDbStoreDatabase::ConstructL() |
|
112 { |
|
113 __ASSERT(iStore); // this must have been provided by now |
|
114 iVersion=TUint8(EDbStoreVersion2); |
|
115 InitPagePoolL(); |
|
116 iPagePool->Create(Store()); |
|
117 iTokenId=Store().ExtendL(); |
|
118 ReplaceTokenL(0); |
|
119 iSchemaId=Store().ExtendL(); |
|
120 Schema().Loaded(); |
|
121 ReplaceSchemaL(); |
|
122 return iSchemaId; |
|
123 } |
|
124 |
|
125 // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method. |
|
126 // Open phase #2: Authenticate the client |
|
127 // |
|
128 EXPORT_C void CDbStoreDatabase::AuthenticateL() |
|
129 { |
|
130 if (!iPagePool) |
|
131 { |
|
132 // first client to open the database, so complete initialisation now |
|
133 InitPagePoolL(); |
|
134 SchemaL(); |
|
135 } |
|
136 } |
|
137 |
|
138 // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method. |
|
139 void CDbStoreDatabase::InitPagePoolL() |
|
140 { |
|
141 iPagePool = new(ELeave) RStorePagePool; |
|
142 } |
|
143 |
|
144 |
|
145 CDbSource* CDbStoreDatabase::OpenL(CStreamStore* aStore,TStreamId aStreamId) |
|
146 { |
|
147 CDbStoreDatabase* self=NewLC(aStore); |
|
148 self->RestoreL(aStreamId); |
|
149 CDbSource* src=self->SourceL(); |
|
150 CleanupStack::Pop(); // self |
|
151 return src; |
|
152 } |
|
153 |
|
154 // |
|
155 // Phase 2 construction for opening a database |
|
156 // Client must still authenticate before it can be used |
|
157 // |
|
158 EXPORT_C void CDbStoreDatabase::RestoreL(TStreamId aStreamId) |
|
159 { |
|
160 __ASSERT(iStore); // this must have been provided by now |
|
161 iSchemaId=aStreamId; |
|
162 // read the databse header for encryption information |
|
163 RStoreReadStream strm; |
|
164 strm.OpenLC(Store(),aStreamId); |
|
165 ReadHeaderL(strm); |
|
166 CleanupStack::PopAndDestroy(); // strm |
|
167 } |
|
168 |
|
169 // |
|
170 // Load the root stream header (up to the security key) |
|
171 // |
|
172 void CDbStoreDatabase::ReadHeaderL(RReadStream& aStream) |
|
173 { |
|
174 TUid uid; |
|
175 aStream>>uid; |
|
176 if (uid!=KDbmsStoreDatabase) |
|
177 __LEAVE(KErrArgument); |
|
178 aStream>>iVersion; |
|
179 switch (iVersion) |
|
180 { |
|
181 case EDbStoreCompressed: |
|
182 aStream>>CompressionL(); |
|
183 break; |
|
184 case EDbStoreVersion2: |
|
185 break; |
|
186 default: |
|
187 __LEAVE(KErrNotSupported); |
|
188 break; |
|
189 } |
|
190 } |
|
191 |
|
192 CDbStoreCompression& CDbStoreDatabase::CompressionL() |
|
193 { |
|
194 CDbStoreCompression* c=iCompression; |
|
195 if (!c) |
|
196 iFilter=iCompression=c=CDbStoreCompression::NewL(); |
|
197 return *c; |
|
198 } |
|
199 |
|
200 EXPORT_C CDbStoreDatabase::~CDbStoreDatabase() |
|
201 { |
|
202 if (iPageCache) |
|
203 { |
|
204 iPagePool->Release(); |
|
205 delete iPageCache; |
|
206 } |
|
207 delete iClusterCache; |
|
208 delete iPagePool; |
|
209 delete iCompression; |
|
210 if (!iSharedStore) |
|
211 delete iStore; |
|
212 } |
|
213 |
|
214 // |
|
215 // Validate the column set first |
|
216 // |
|
217 EXPORT_C CDbTableDef* CDbStoreDatabase::CreateTableL(const TDesC& aName,const CDbColSet& aColSet,const CDbKey* aPrimaryKey) |
|
218 { |
|
219 if (aPrimaryKey) |
|
220 __LEAVE(KErrNotSupported); // Store database does not support primary keys |
|
221 CDbStoreDef* def=CDbStoreDef::NewLC(aName,aColSet); |
|
222 def->SetTokenId(CDbStoreRecords::CreateL(ClusterCacheL())); |
|
223 CleanupStack::Pop(); |
|
224 return def; |
|
225 } |
|
226 |
|
227 EXPORT_C CDbTableIndexDef* CDbStoreDatabase::CreateIndexL(const CDbTableDef& aTable,const TDesC& aName,const CDbKey& aKey) |
|
228 { |
|
229 CDbStoreIndexDef* def=CDbStoreIndexDef::NewLC(aName,aKey,aTable.Columns()); |
|
230 def->SetTokenId(CDbStoreIndex::CreateL(*this,*def)); |
|
231 CleanupStack::Pop(); // IndexDef |
|
232 return def; |
|
233 } |
|
234 |
|
235 // |
|
236 // Destroy the entire database... |
|
237 // |
|
238 EXPORT_C void CDbStoreDatabase::DestroyL() |
|
239 { |
|
240 iPagePool->Discard(); |
|
241 iPagePool->ReclaimAllL(); // reclaim all page pool space |
|
242 iStore->DeleteL(iSchemaId); |
|
243 iStore->DeleteL(iTokenId); |
|
244 iStore->CommitL(); |
|
245 } |
|
246 |
|
247 EXPORT_C CDbTable* CDbStoreDatabase::TableL(const CDbTableDef& aDef) |
|
248 { |
|
249 return new(ELeave) CDbStoreTable(*this,aDef); |
|
250 } |
|
251 |
|
252 // |
|
253 // load the schema for the database |
|
254 // |
|
255 EXPORT_C void CDbStoreDatabase::LoadSchemaL() |
|
256 { |
|
257 RDbStoreReadStream strm(*this); |
|
258 strm.OpenLC(Store(),iSchemaId); |
|
259 ReadHeaderL(strm); |
|
260 strm.FilterL(strm.EMixed,iSchemaId.Value()); |
|
261 strm>>iTokenId; |
|
262 RDbTableSchema& schema=Schema(); |
|
263 TCardinality tables; |
|
264 strm>>tables; |
|
265 for (TInt ii=tables;ii>0;--ii) |
|
266 schema.Add(CDbStoreDef::NewL(strm)); |
|
267 CleanupStack::PopAndDestroy(); |
|
268 strm.OpenLC(Store(),iTokenId); |
|
269 strm>>iFlags>>iPoolToken; |
|
270 iPagePool->Open(Store(),iPoolToken); |
|
271 CleanupStack::PopAndDestroy(); |
|
272 } |
|
273 |
|
274 // |
|
275 // Re-write the schema stream |
|
276 // |
|
277 void CDbStoreDatabase::ReplaceSchemaL() |
|
278 { |
|
279 RDbStoreWriteStream out(*this); |
|
280 out.ReplaceLC(Store(),iSchemaId); |
|
281 out<<KDbmsStoreDatabase<<iVersion; |
|
282 switch (iVersion) |
|
283 { |
|
284 case EDbStoreCompressed: |
|
285 __ASSERT(iCompression); |
|
286 out<<*iCompression; |
|
287 break; |
|
288 case EDbStoreVersion2: |
|
289 break; |
|
290 default: |
|
291 __ASSERT(0); |
|
292 } |
|
293 out.FilterL(out.EMixed,iSchemaId.Value()); |
|
294 out<<iTokenId; |
|
295 TSglQueIterC<CDbStoreDef> iter(Schema()); |
|
296 TInt count=0; |
|
297 while (iter++) |
|
298 ++count; |
|
299 out<<TCardinality(count); |
|
300 iter.SetToFirst(); |
|
301 for (const CDbStoreDef* def;(def=iter++)!=0;) |
|
302 out<<*def; |
|
303 out.CommitL(); |
|
304 CleanupStack::PopAndDestroy(); |
|
305 } |
|
306 |
|
307 // |
|
308 // Re-write the token stream, removing the mark |
|
309 // |
|
310 void CDbStoreDatabase::ReplaceTokenL(TUint aFlags) |
|
311 { |
|
312 RStoreWriteStream out; |
|
313 out.ReplaceLC(Store(),iTokenId); |
|
314 out<<TUint8(aFlags&EDamaged)<<iPagePool->Token(); |
|
315 out.CommitL(); |
|
316 CleanupStack::PopAndDestroy(); |
|
317 } |
|
318 |
|
319 // |
|
320 // Return some database property |
|
321 // |
|
322 EXPORT_C TInt CDbStoreDatabase::Property(CDbDatabase::TProperty aProperty) |
|
323 { |
|
324 switch (aProperty) |
|
325 { |
|
326 case CDbDatabase::EIsDamaged: |
|
327 return iFlags&EDamaged ? 1 : 0; |
|
328 case CDbDatabase::ECompactable: |
|
329 return 1; |
|
330 default: |
|
331 return CDbTableDatabase::Property(aProperty); |
|
332 } |
|
333 } |
|
334 |
|
335 // |
|
336 // mark the database as dirty |
|
337 // |
|
338 void CDbStoreDatabase::MarkL() |
|
339 { |
|
340 if (!(iFlags&EModified)) |
|
341 { |
|
342 RStoreWriteStream out; |
|
343 out.OpenLC(Store(),iTokenId); |
|
344 out.WriteUint8L(EDamaged); // mark as dirty |
|
345 iPoolToken.Touch(); |
|
346 out<<iPoolToken; |
|
347 out.CommitL(); |
|
348 CleanupStack::PopAndDestroy(); |
|
349 iFlags|=EModified; |
|
350 } |
|
351 } |
|
352 |
|
353 // |
|
354 // Reset all cache buffers |
|
355 // |
|
356 EXPORT_C void CDbStoreDatabase::Idle() |
|
357 { |
|
358 if (iPageCache) |
|
359 { |
|
360 iPagePool->Purge(); |
|
361 delete iPageCache; |
|
362 iPageCache=NULL; |
|
363 } |
|
364 if (iClusterCache) |
|
365 { |
|
366 delete iClusterCache; |
|
367 iClusterCache=NULL; |
|
368 } |
|
369 } |
|
370 |
|
371 // |
|
372 // Commit the store, and when all is well, clear the token |
|
373 // |
|
374 void CDbStoreDatabase::SynchStoreL(TDbLockType aLock) |
|
375 { |
|
376 if (iPageCache) |
|
377 iPagePool->FlushL(); |
|
378 TUint newflags=iFlags&~EModified; |
|
379 if (aLock==EDbRecoveryLock) |
|
380 newflags&=~EDamaged; |
|
381 if (aLock==EDbRecoveryLock || iFlags&EModified) |
|
382 ReplaceTokenL(newflags); |
|
383 if (aLock>=EDbWriteLock || iSharedStore) |
|
384 { |
|
385 iStore->CommitL(); |
|
386 iFlags=TUint8(newflags); |
|
387 iPoolToken=iPagePool->Token(); |
|
388 } |
|
389 } |
|
390 |
|
391 // |
|
392 // An index has been successfully recovered, commit it |
|
393 // |
|
394 void CDbStoreDatabase::IndexRecoveredL() |
|
395 { |
|
396 SynchStoreL(EDbSchemaLock); |
|
397 } |
|
398 |
|
399 // |
|
400 // Ensure all data is in the store |
|
401 // |
|
402 EXPORT_C void CDbStoreDatabase::SynchL(TDbLockType aLock) |
|
403 { |
|
404 if (aLock==EDbSchemaLock) |
|
405 ReplaceSchemaL(); |
|
406 if (iClusterCache) |
|
407 iClusterCache->FlushL(); |
|
408 SynchStoreL(aLock); |
|
409 } |
|
410 |
|
411 // |
|
412 // Unwind the store, throw out changes, etc |
|
413 // |
|
414 EXPORT_C void CDbStoreDatabase::Revert(TDbLockType aLock) |
|
415 { |
|
416 if (aLock>=EDbWriteLock) |
|
417 { |
|
418 if (iClusterCache) |
|
419 iClusterCache->Discard(); |
|
420 if (iPageCache) |
|
421 iPagePool->Purge(); |
|
422 if (iFlags&EModified) |
|
423 iFlags|=EDamaged; |
|
424 iPagePool->Open(Store(),iPoolToken); // reset the page pool |
|
425 } |
|
426 else if (!iSharedStore) // don't touch the store if not shared |
|
427 return; |
|
428 iStore->Revert(); |
|
429 } |
|
430 |
|
431 // |
|
432 // Ensure we have a cluster cache and return it |
|
433 // |
|
434 CClusterCache& CDbStoreDatabase::ClusterCacheL() |
|
435 { |
|
436 CClusterCache* cache=iClusterCache; |
|
437 if (!cache) |
|
438 iClusterCache=cache=CClusterCache::NewL(*this); |
|
439 return *cache; |
|
440 } |
|
441 |
|
442 // |
|
443 // Ensure we have a page cache and return the pool |
|
444 // |
|
445 MPagePool& CDbStoreDatabase::PagePoolL() |
|
446 { |
|
447 if (!iPageCache) |
|
448 { |
|
449 iPageCache=CPageCache::NewL(EPageCachePages); |
|
450 iPagePool->Set(*iPageCache); |
|
451 } |
|
452 return *iPagePool; |
|
453 } |
|
454 |
|
455 // |
|
456 // Create an incremental object that compacts the store |
|
457 // |
|
458 EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::UtilityL(CDbDatabase::TUtility aType,TInt& aStep) |
|
459 { |
|
460 switch (aType) |
|
461 { |
|
462 case CDbDatabase::EStats: |
|
463 case CDbDatabase::ECompact: |
|
464 return CCompactor::NewL(aType,Store(),iReclaim,aStep); |
|
465 case CDbDatabase::ERecover: |
|
466 return RecoverL(aStep); |
|
467 default: |
|
468 return CDbTableDatabase::UtilityL(aType,aStep); |
|
469 } |
|
470 } |
|
471 |
|
472 // |
|
473 // Create an incremental object to destroy a table |
|
474 // |
|
475 EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::RecordDiscarderL(const CDbTableDef& aTable,TInt& aStep) |
|
476 { |
|
477 CDbStoreTable::CDiscarder* discarder=new(ELeave) CDbStoreTable::CDiscarder; |
|
478 CleanupStack::PushL(discarder); |
|
479 aStep=discarder->OpenL((CDbStoreTable*)TableL(aTable)); |
|
480 CleanupStack::Pop(); |
|
481 return discarder; |
|
482 } |
|
483 |
|
484 // |
|
485 // Create an incremental object to destroy an index |
|
486 // |
|
487 EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::IndexDiscarderL(const CDbTableDef& aTable,const CDbTableIndexDef& anIndex,TInt& aStep) |
|
488 { |
|
489 CDbStoreIndex::CDiscarder* discarder=new(ELeave) CDbStoreIndex::CDiscarder; |
|
490 CleanupStack::PushL(discarder); |
|
491 CDbStoreIndex* index=CDbStoreIndex::NewL(*this,(const CDbStoreIndexDef&)anIndex,aTable); |
|
492 aStep=discarder->Open(index); |
|
493 index->OpenL(); |
|
494 CleanupStack::Pop(); |
|
495 return discarder; |
|
496 } |
|
497 |
|
498 // |
|
499 // Provide a stepper to alter the table data |
|
500 // if no data to alter, return 0 |
|
501 // |
|
502 EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::TableAlterL(CDbTableDef& aTable,const HDbColumnSet& aNewSet,TInt& aStep) |
|
503 { |
|
504 CDbStoreDef& def=STATIC_CAST(CDbStoreDef&,aTable); |
|
505 // |
|
506 aStep=CDbStoreRecords::CardinalityL(Store(),def); |
|
507 if (!aStep) |
|
508 return NULL; // no data to modify |
|
509 |
|
510 // check that all added columns are nullable |
|
511 HDbColumnSet::TIteratorC col=aNewSet.Begin(); |
|
512 HDbColumnSet::TIteratorC end=aNewSet.End(); |
|
513 do |
|
514 { |
|
515 if (col->iFlags&TDbColumnDef::EAdded && col->iAttributes&TDbCol::ENotNull) |
|
516 __LEAVE(KErrArgument); // added column is not nullable |
|
517 } while (++col<end); |
|
518 // |
|
519 // check to see if anything is being dropped or changed type |
|
520 col=aTable.Columns().Begin(); |
|
521 end=aTable.Columns().End(); |
|
522 while (!(col->iFlags&(TDbColumnDef::EDropped|TDbColumnDef::EChangedType|TDbColumnDef::EChangedLen))) |
|
523 { |
|
524 if (++col==end) |
|
525 { // no changes which affect layout, so no work required |
|
526 aStep=0; |
|
527 return NULL; |
|
528 } |
|
529 } |
|
530 // work required |
|
531 CDbStoreTable::CAlter* alter=new(ELeave) CDbStoreTable::CAlter; |
|
532 CleanupStack::PushL(alter); |
|
533 alter->OpenL((CDbStoreTable*)TableL(def),aNewSet); |
|
534 CleanupStack::Pop(); |
|
535 return alter; |
|
536 } |
|
537 |
|
538 EXPORT_C void CDbStoreDatabase::Reserved_1() |
|
539 { |
|
540 } |
|
541 |
|
542 EXPORT_C void CDbStoreDatabase::Reserved_2() |
|
543 { |
|
544 } |
|
545 |