|
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 "UT_STD.H" |
|
17 |
|
18 #define UNUSED_VAR(a) a = a |
|
19 |
|
20 const TUint KTableExpiry=0x100000; // ~1.0s |
|
21 |
|
22 // Class Blob cleanup |
|
23 |
|
24 NONSHARABLE_CLASS(CDbBlobCleanup) : public CArrayFixFlat<TDbBlobId> |
|
25 { |
|
26 public: |
|
27 static CDbBlobCleanup* NewLC(CDbBlobSpace& aBlobSpace); |
|
28 ~CDbBlobCleanup(); |
|
29 private: |
|
30 inline CDbBlobCleanup(CDbBlobSpace& aBlobSpace); |
|
31 private: |
|
32 CDbBlobSpace& iBlobSpace; |
|
33 }; |
|
34 |
|
35 inline CDbBlobCleanup::CDbBlobCleanup(CDbBlobSpace& aBlobSpace) |
|
36 : CArrayFixFlat<TDbBlobId>(8),iBlobSpace(aBlobSpace) |
|
37 {} |
|
38 |
|
39 CDbBlobCleanup* CDbBlobCleanup::NewLC(CDbBlobSpace& aBlobSpace) |
|
40 { |
|
41 CDbBlobCleanup* self=new(ELeave) CDbBlobCleanup(aBlobSpace); |
|
42 CleanupStack::PushL(self); |
|
43 return self; |
|
44 } |
|
45 |
|
46 CDbBlobCleanup::~CDbBlobCleanup() |
|
47 { |
|
48 TInt count=Count(); |
|
49 if (count) |
|
50 { |
|
51 const TDbBlobId* blob=&(*this)[0]; |
|
52 const TDbBlobId* const end=blob+count; |
|
53 for (;blob<end;++blob) |
|
54 iBlobSpace.Delete(*blob); |
|
55 } |
|
56 } |
|
57 |
|
58 // Class CDbTable |
|
59 |
|
60 |
|
61 EXPORT_C CDbTable::CDbTable(CDbTableDatabase& aDatabase,const CDbTableDef& aDef) |
|
62 : iDatabase(&aDatabase),iDef(&aDef) |
|
63 { |
|
64 aDatabase.Open(); |
|
65 aDatabase.AddTable(*this); // we reference database |
|
66 } |
|
67 |
|
68 EXPORT_C CDbTable::~CDbTable() |
|
69 // |
|
70 // Destroy components |
|
71 // |
|
72 { |
|
73 __ASSERT(!InUse()); // cannot be directly deleted |
|
74 if (IsActive()) |
|
75 Disconnect(); |
|
76 } |
|
77 |
|
78 void CDbTable::Disconnect() |
|
79 // |
|
80 // Disconnect the table from the database collection. |
|
81 // |
|
82 { |
|
83 __ASSERT(IsActive()); |
|
84 Database().RemoveTable(*this); |
|
85 TRAPD(errCode, ApplyToComponentsL(CDbRecordBase::DoDelete)); |
|
86 UNUSED_VAR(errCode); |
|
87 } |
|
88 |
|
89 void CDbTable::Open() |
|
90 { |
|
91 __ASSERT(IsActive()); |
|
92 TInt r=++iRef; |
|
93 if (r<=0) |
|
94 { // were idle or cached |
|
95 if (r<0) |
|
96 { |
|
97 Cache().Release(*this); // was cached |
|
98 iRef=0; |
|
99 } |
|
100 Database().Open(); |
|
101 } |
|
102 } |
|
103 |
|
104 void CDbTable::Close() |
|
105 // |
|
106 // We may destroy this object when the last reference goes away |
|
107 // |
|
108 { |
|
109 __ASSERT(InUse()); |
|
110 if (--iRef<0) |
|
111 { |
|
112 if (!IsActive()) |
|
113 delete this; // disconnected table |
|
114 else |
|
115 { |
|
116 CDbTableDatabase& db=Database(); |
|
117 if (!db.Transaction().IsLocked()) |
|
118 Idle(); // no transaction, idle now |
|
119 db.Close(); // this must be done last to avoid early self destruction |
|
120 } |
|
121 } |
|
122 } |
|
123 |
|
124 void CDbTable::Idle() |
|
125 // |
|
126 // Called when idle, change to cached state |
|
127 // |
|
128 { |
|
129 __ASSERT(IsIdle()); |
|
130 __ASSERT(IsActive()); |
|
131 // |
|
132 iRef=ECached; |
|
133 Cache().Hold(this,KTableExpiry); // may delete this |
|
134 } |
|
135 |
|
136 void CDbTable::FlushL() |
|
137 // |
|
138 // Ensure all records objects are flushed |
|
139 // |
|
140 { |
|
141 __ASSERT(IsActive()); |
|
142 if (iRef!=ECached) |
|
143 ApplyToComponentsL(CDbRecordBase::DoFlushL); |
|
144 } |
|
145 |
|
146 void CDbTable::Abandon() |
|
147 // |
|
148 // Discard all components |
|
149 // |
|
150 { |
|
151 __ASSERT(IsActive()); |
|
152 TRAPD(errCode, ApplyToComponentsL(CDbRecordBase::DoAbandon)); |
|
153 UNUSED_VAR(errCode); |
|
154 iIndexesEnd=NULL; // flags indexes as abandoned |
|
155 ++iGeneration; |
|
156 } |
|
157 |
|
158 void CDbTable::Release() |
|
159 // |
|
160 // Release the table and all its cursors as DDL is about to begin |
|
161 // |
|
162 { |
|
163 __ASSERT(IsActive()); |
|
164 switch (iRef) |
|
165 { |
|
166 case ECached: |
|
167 Cache().Release(*this); |
|
168 // fall throught to Idle |
|
169 case EIdle: |
|
170 delete this; |
|
171 break; |
|
172 default: |
|
173 __ASSERT(InUse()); |
|
174 Database().Close(); |
|
175 Disconnect(); |
|
176 iDatabase=0; // this marks us as released |
|
177 iDef=0; |
|
178 break; |
|
179 } |
|
180 } |
|
181 |
|
182 void CDbTable::ApplyToBlobsL(RDbRow& aRow,TBlobFuncL aFuncL,CDbBlobCleanup* aCleanup) |
|
183 { |
|
184 __ASSERT(Def().Columns().HasLongColumns()); |
|
185 CDbBlobSpace* blobs=BlobsL(); |
|
186 __ASSERT(blobs); |
|
187 TDbColNo col=1; |
|
188 HDbColumnSet::TIteratorC iter=Def().Columns().Begin(); |
|
189 const HDbColumnSet::TIteratorC end=Def().Columns().End(); |
|
190 do |
|
191 { |
|
192 if (!TDbCol::IsLong(iter->Type())) |
|
193 continue; |
|
194 const TDbColumnC column(aRow,col); |
|
195 if (column.IsNull()) |
|
196 continue; |
|
197 aFuncL(*blobs,CONST_CAST(TDbBlob&,column.Blob()),iter->Type(),aCleanup); |
|
198 } while (++col,++iter<end); |
|
199 } |
|
200 |
|
201 LOCAL_C void DuplicateBlobL(CDbBlobSpace& aBlobStore,TDbBlob& aBlob,TDbColType aType,CDbBlobCleanup* aCleanup) |
|
202 { |
|
203 __ASSERT(aCleanup); |
|
204 if (aBlob.IsInline()) |
|
205 return; |
|
206 // need to duplicate blob |
|
207 RReadStream old(aBlobStore.ReadLC(aBlob.Id(),aType)); |
|
208 TDbBlobId& newId=aCleanup->ExtendL(); |
|
209 newId=KDbNullBlobId; |
|
210 RWriteStream dup(aBlobStore.CreateL(newId,aType)); |
|
211 dup.PushL(); |
|
212 dup.WriteL(old,aBlob.Size()); |
|
213 dup.CommitL(); |
|
214 CleanupStack::PopAndDestroy(2); // old and dup streams |
|
215 aBlob.SetId(newId); // row is writable |
|
216 } |
|
217 |
|
218 void CDbTable::DuplicateBlobsL(RDbRow& aRow) |
|
219 // |
|
220 // duplicate any blobs |
|
221 // |
|
222 { |
|
223 if (!Def().Columns().HasLongColumns()) |
|
224 return; |
|
225 |
|
226 CDbBlobCleanup* cleaner=CDbBlobCleanup::NewLC(*BlobsL()); |
|
227 ApplyToBlobsL(aRow,DuplicateBlobL,cleaner); |
|
228 cleaner->Reset(); |
|
229 CleanupStack::PopAndDestroy(); |
|
230 } |
|
231 |
|
232 TBool CDbTable::ExistsL(TDbRecordId aRecordId) |
|
233 // |
|
234 // Check that aRecordId is good for this table |
|
235 // |
|
236 { |
|
237 __ASSERT(IsActive() && InUse()); |
|
238 return RecordsL().ExistsL(aRecordId); |
|
239 } |
|
240 |
|
241 void CDbTable::NewRowL(RDbRow& aRow) |
|
242 // |
|
243 // Initialise any auto-increment columns in the row |
|
244 // |
|
245 { |
|
246 const HDbColumnSet& columns=Def().Columns(); |
|
247 if (!columns.HasAutoIncrement()) |
|
248 return; |
|
249 |
|
250 TUint value=RecordsL().AutoIncrementL(); |
|
251 TDbColNo col=1; |
|
252 HDbColumnSet::TIteratorC iter=columns.Begin(); |
|
253 const HDbColumnSet::TIteratorC end=columns.End(); |
|
254 do |
|
255 { |
|
256 if (iter->iAttributes&TDbCol::EAutoIncrement) |
|
257 { |
|
258 // auto-increment only for integral types <=32 bits wide |
|
259 __ASSERT(iter->iType<=EDbColUint32); |
|
260 TDbColumn column(aRow,col); |
|
261 column.SetL(TUint32(value)); |
|
262 } |
|
263 } while (++col,++iter<end); |
|
264 } |
|
265 |
|
266 void CDbTable::ValidateL(const RDbRow& aRow) |
|
267 // |
|
268 // Ensure that the column data conforms to type size/flags etc |
|
269 // |
|
270 { |
|
271 HDbColumnSet::TIteratorC iter=Def().Columns().Begin(); |
|
272 const HDbColumnSet::TIteratorC end=Def().Columns().End(); |
|
273 const TDbCell* const last=aRow.Last(); |
|
274 for (const TDbCell* column=aRow.First();column<last;++iter,column=column->Next()) |
|
275 { |
|
276 TInt size=column->Length(); |
|
277 if (size==0) |
|
278 { // check for Null |
|
279 if (iter->iAttributes&TDbCol::ENotNull) |
|
280 { |
|
281 __LEAVE(KErrNotFound); |
|
282 return; |
|
283 } |
|
284 continue; |
|
285 } |
|
286 const TUint32* data=(const TUint32*)column->Data(); |
|
287 switch (iter->iType) |
|
288 { |
|
289 case EDbColBit: |
|
290 if (*data>1) |
|
291 __LEAVE(KErrOverflow); |
|
292 break; |
|
293 case EDbColInt8: |
|
294 { |
|
295 TInt val=*data; |
|
296 if (TInt8(val)!=val) |
|
297 __LEAVE(KErrOverflow); |
|
298 } |
|
299 break; |
|
300 case EDbColInt16: |
|
301 { |
|
302 TInt val=*data; |
|
303 if (TInt16(val)!=val) |
|
304 __LEAVE(KErrOverflow); |
|
305 } |
|
306 break; |
|
307 case EDbColUint8: |
|
308 { |
|
309 TUint val=*data; |
|
310 if (TUint8(val)!=val) |
|
311 __LEAVE(KErrOverflow); |
|
312 } |
|
313 break; |
|
314 case EDbColUint16: |
|
315 { |
|
316 TUint val=*data; |
|
317 if (TUint16(val)!=val) |
|
318 __LEAVE(KErrOverflow); |
|
319 } |
|
320 break; |
|
321 case EDbColText16: |
|
322 size>>=1; |
|
323 case EDbColBinary: |
|
324 case EDbColText8: |
|
325 if (iter->iMaxLength==KDbUndefinedLength) |
|
326 break; |
|
327 if (size>iter->iMaxLength) |
|
328 __LEAVE(KErrOverflow); |
|
329 break; |
|
330 case EDbColLongBinary: |
|
331 case EDbColLongText8: |
|
332 case EDbColLongText16: |
|
333 if (iter->iMaxLength==KDbUndefinedLength) |
|
334 break; |
|
335 size=((TDbBlob*)data)->Size(); |
|
336 if (size==KDbUndefinedLength) |
|
337 break; |
|
338 if (iter->iType==EDbColText16) |
|
339 size>>=1; |
|
340 if (size>iter->iMaxLength) |
|
341 __LEAVE(KErrOverflow); |
|
342 break; |
|
343 default: |
|
344 break; |
|
345 } |
|
346 } |
|
347 for (;iter<end;++iter) |
|
348 { // check for Null |
|
349 if (iter->iAttributes&TDbCol::ENotNull) |
|
350 { |
|
351 __LEAVE(KErrNotFound); |
|
352 return; |
|
353 } |
|
354 } |
|
355 } |
|
356 |
|
357 void CDbTable::ReadRowL(RDbRow& aRow,TDbRecordId aRecordId) |
|
358 // |
|
359 // Read a record from the table |
|
360 // |
|
361 { |
|
362 CopyToRowL(aRow,RecordsL().ReadL(aRecordId)); |
|
363 } |
|
364 |
|
365 void CDbTable::PrepareAppendL(const RDbTableRow& aRow) |
|
366 // |
|
367 // Validate a new record for appending |
|
368 // |
|
369 { |
|
370 EnsureIndexesL(); |
|
371 ValidateL(aRow); |
|
372 CDbRecordIndex** end=iIndexesEnd; |
|
373 for (CDbRecordIndex** pix=iIndexes;pix<end;++pix) |
|
374 { |
|
375 CDbRecordIndex& ix=**pix; |
|
376 if (ix.IsBroken()) |
|
377 continue; |
|
378 if (ix.FindL(KDbNullRecordId,aRow)==CDbRecordIndex::EKeyMatch) |
|
379 __LEAVE(KErrAlreadyExists); // duplicate found |
|
380 } |
|
381 } |
|
382 |
|
383 TDbRecordId CDbTable::AppendRowL(const RDbTableRow& aRow) |
|
384 // |
|
385 // Validate and add a new record to the table and any open indexes |
|
386 // |
|
387 { |
|
388 CDbRecordSpace& records=RecordsL(); |
|
389 CopyFromRow(records.NewL(RecordLength(aRow)),aRow); |
|
390 TDbRecordId id=records.AppendL(); |
|
391 CDbRecordIndex** end=iIndexesEnd; |
|
392 for (CDbRecordIndex** pix=iIndexes;pix<end;++pix) |
|
393 { |
|
394 CDbRecordIndex& ix=**pix; |
|
395 if (ix.IsBroken()) |
|
396 continue; |
|
397 __DEBUG(TInt dbgchk=) ix.InsertL(id,aRow); |
|
398 __ASSERT(dbgchk); |
|
399 } |
|
400 ++iGeneration; |
|
401 return id; |
|
402 } |
|
403 |
|
404 void CDbTable::PrepareReplaceL(const RDbTableRow& aRow,TDbRecordId aRecordId) |
|
405 // |
|
406 // Validate a record for replacement |
|
407 // |
|
408 { |
|
409 EnsureIndexesL(); |
|
410 ValidateL(aRow); |
|
411 TUint32 update=0; |
|
412 CDbRecordIndex** end=iIndexes; |
|
413 for (CDbRecordIndex** pix=iIndexesEnd;--pix>=end;) |
|
414 { |
|
415 update<<=1; |
|
416 CDbRecordIndex& ix=**pix; |
|
417 if (ix.IsBroken()) |
|
418 continue; |
|
419 switch (ix.FindL(aRecordId,aRow)) |
|
420 { |
|
421 case CDbRecordIndex::ENoMatch: // key has changed in index |
|
422 update|=1; |
|
423 break; |
|
424 case CDbRecordIndex::EKeyMatch: // duplicate found |
|
425 __LEAVE(KErrAlreadyExists); |
|
426 case CDbRecordIndex::EEntryMatch: // no change in index |
|
427 break; |
|
428 } |
|
429 } |
|
430 iUpdateMap=update; |
|
431 } |
|
432 |
|
433 void CDbTable::DoReplaceRowL(const RDbRow& aRow,TDbRecordId aRecordId) |
|
434 { |
|
435 CopyFromRow(RecordsL().ReplaceL(aRecordId,RecordLength(aRow)),aRow); |
|
436 ++iGeneration; |
|
437 } |
|
438 |
|
439 void CDbTable::ReplaceRowL(RDbTableRow& aRow,TDbRecordId aRecordId) |
|
440 // |
|
441 // Replace a record in the table |
|
442 // |
|
443 { |
|
444 if (Def().Columns().HasLongColumns()) |
|
445 CheckInliningL(aRow); |
|
446 TUint32 update=iUpdateMap; |
|
447 if (update==0) |
|
448 { |
|
449 DoReplaceRowL(aRow,aRecordId); |
|
450 return; |
|
451 } |
|
452 RDbTableRow oldRow; // temporary row buffer for old row values |
|
453 oldRow.Open(this); |
|
454 oldRow.PushL(); // cleanup buffer if there is trouble |
|
455 ReadRowL(oldRow,aRecordId); |
|
456 DoReplaceRowL(aRow,aRecordId); |
|
457 for (CDbRecordIndex** pix=iIndexes;update;++pix,update>>=1) |
|
458 { |
|
459 if (update&1) |
|
460 { |
|
461 CDbRecordIndex& index=**pix; |
|
462 index.DeleteL(aRecordId,oldRow); |
|
463 __DEBUG(TInt dbgchk=) index.InsertL(aRecordId,aRow); |
|
464 __ASSERT(dbgchk); |
|
465 } |
|
466 } |
|
467 CleanupStack::PopAndDestroy(); // temp row buffer |
|
468 } |
|
469 |
|
470 LOCAL_C void CheckInlineL(CDbBlobSpace& aBlobStore,TDbBlob& aBlob,TDbColType aType,CDbBlobCleanup*) |
|
471 { |
|
472 if (!aBlob.IsInline()) |
|
473 return; |
|
474 if (aBlob.Size()>aBlobStore.InlineLimit()) |
|
475 aBlob.SetId(aBlobStore.CreateL(aType,aBlob.Data(),aBlob.Size())); |
|
476 } |
|
477 |
|
478 void CDbTable::CheckInliningL(RDbRow& aRow) |
|
479 // |
|
480 // Ensure that all Blobs are within the current inline limit |
|
481 // |
|
482 { |
|
483 ApplyToBlobsL(aRow,CheckInlineL); |
|
484 } |
|
485 |
|
486 LOCAL_C void DiscardBlobL(CDbBlobSpace& aBlobStore,TDbBlob& aBlob,TDbColType,CDbBlobCleanup*) |
|
487 { |
|
488 if (!aBlob.IsInline()) |
|
489 aBlobStore.DeleteL(aBlob.Id()); |
|
490 } |
|
491 |
|
492 EXPORT_C void CDbTable::DiscardBlobsL(RDbRow& aRow) |
|
493 // |
|
494 // Default implemtation xlates the record and then walks the row buffer |
|
495 // |
|
496 { |
|
497 ApplyToBlobsL(aRow,DiscardBlobL); |
|
498 } |
|
499 |
|
500 void CDbTable::DeleteRowL(RDbTableRow& aRow,TDbRecordId aRecordId) |
|
501 // |
|
502 // Delete the record from the file and unlock it. |
|
503 // |
|
504 { |
|
505 EnsureIndexesL(); |
|
506 |
|
507 if (Def().Columns().HasLongColumns()) |
|
508 { |
|
509 // Read data from the stream but do not delete the stream yet. |
|
510 aRow.ReadL(aRecordId); |
|
511 } |
|
512 |
|
513 CDbRecordIndex** end=iIndexes; |
|
514 CDbRecordIndex** pix=iIndexesEnd; |
|
515 if (pix!=end) |
|
516 aRow.ReadL(aRecordId); |
|
517 RecordsL().EraseL(aRecordId); |
|
518 while (--pix>=end) |
|
519 { |
|
520 CDbRecordIndex& ix=**pix; |
|
521 if (!ix.IsBroken()) |
|
522 ix.DeleteL(aRecordId,aRow); |
|
523 } |
|
524 |
|
525 if (Def().Columns().HasLongColumns()) |
|
526 { |
|
527 // Now delete the stream. |
|
528 DiscardBlobsL(aRow); |
|
529 } |
|
530 |
|
531 ++iGeneration; |
|
532 } |
|
533 |
|
534 EXPORT_C CDbRecordSpace& CDbTable::RecordsL() |
|
535 { |
|
536 __ASSERT(IsActive() && InUse()); |
|
537 CDbRecordSpace* rec=iRecords; |
|
538 if (rec==NULL) |
|
539 iRecords=rec=RecordSpaceL(); |
|
540 if (rec->OpenL()) |
|
541 __LEAVE(KErrCorrupt); |
|
542 return *rec; |
|
543 } |
|
544 |
|
545 EXPORT_C CDbBlobSpace* CDbTable::BlobsL() |
|
546 { |
|
547 __ASSERT(IsActive() && InUse()); |
|
548 CDbBlobSpace* blob=iBlobs; |
|
549 if (blob==NULL) |
|
550 iBlobs=blob=BlobSpaceL(); |
|
551 if (blob->OpenL()) |
|
552 __LEAVE(KErrCorrupt); |
|
553 return blob; |
|
554 } |
|
555 |
|
556 EXPORT_C CDbRecordIndex& CDbTable::IndexL(const CDbTableIndexDef& aIndex) |
|
557 // |
|
558 // Load the index associated with the index definition and ensure it is operational |
|
559 // |
|
560 { |
|
561 __ASSERT(IsActive() && InUse()); |
|
562 // find the matching slot in the indexes array |
|
563 CDbRecordIndex** slot=&iIndexes[0]; |
|
564 for (TSglQueIterC<CDbTableIndexDef> iter(Def().Indexes().AsQue());iter++!=&aIndex;) |
|
565 ++slot; |
|
566 __ASSERT(iIndexesEnd==NULL||(slot>=iIndexes&&slot<iIndexesEnd)); |
|
567 // load (if required) and open the index |
|
568 CDbRecordIndex* index=*slot; |
|
569 if (index==0) |
|
570 *slot=index=RecordIndexL(aIndex); |
|
571 if (index->OpenL()) |
|
572 __LEAVE(KErrCorrupt); |
|
573 return *index; |
|
574 } |
|
575 |
|
576 void CDbTable::EnsureIndexesL() |
|
577 // |
|
578 // Ensure that all indexes are open |
|
579 // |
|
580 { |
|
581 __ASSERT(IsActive() && InUse()); |
|
582 if (iIndexesEnd==NULL) |
|
583 { |
|
584 CDbRecordIndex** pp=iIndexes; |
|
585 TSglQueIterC<CDbTableIndexDef> iter(Def().Indexes().AsQue()); |
|
586 for (const CDbTableIndexDef* xDef;(xDef=iter++)!=NULL;++pp) |
|
587 { |
|
588 CDbRecordIndex* ix=*pp; |
|
589 if (ix==NULL) |
|
590 *pp=ix=RecordIndexL(*xDef); |
|
591 ix->OpenL(); // ignore broken-ness |
|
592 } |
|
593 iIndexesEnd=pp; |
|
594 } |
|
595 } |
|
596 |
|
597 CDbRecordIter* CDbTable::IteratorL() |
|
598 { |
|
599 return RecordsL().IteratorL(); |
|
600 } |
|
601 |
|
602 CDbRecordIter* CDbTable::IteratorL(const CDbTableIndexDef& aIndex,TUint aInclusion,const TDbLookupKey* aLowerBound,const TDbLookupKey* aUpperBound) |
|
603 // |
|
604 // create an interator for the index parameter |
|
605 // |
|
606 { |
|
607 return IndexL(aIndex).IteratorL(aInclusion,aLowerBound,aUpperBound); |
|
608 } |
|
609 |
|
610 EXPORT_C TInt CDbTable::IndexSpanL(const CDbTableIndexDef&,TUint,const TDbLookupKey*,const TDbLookupKey*) |
|
611 // |
|
612 // Default implementation: no statistics are available |
|
613 // |
|
614 { |
|
615 return EUnavailableSpan; |
|
616 } |
|
617 |
|
618 CDbRecordIter* CDbTable::IteratorL(const TDesC& aIndex) |
|
619 // |
|
620 // create an interator for the index named |
|
621 // |
|
622 { |
|
623 return IteratorL(Def().Indexes().FindL(aIndex)); |
|
624 } |
|
625 |
|
626 void CDbTable::ApplyToComponentsL(void (*anOperationL)(CDbRecordBase*)) |
|
627 // |
|
628 // Invoke anOperation on all components of the table |
|
629 // |
|
630 { |
|
631 if (iRecords) |
|
632 anOperationL(iRecords); |
|
633 if (iBlobs) |
|
634 anOperationL(iBlobs); |
|
635 CDbRecordIndex** const ixs=iIndexes; |
|
636 CDbRecordIndex** pix=iIndexesEnd; |
|
637 if (pix==NULL) |
|
638 pix=&iIndexes[KDbTableMaxIndexes]; |
|
639 while (--pix>=ixs) |
|
640 if (*pix) |
|
641 anOperationL(*pix); |
|
642 } |
|
643 |
|
644 // Class CDbtable::TValid |
|
645 |
|
646 // this class is used by the cursor to check that it is still operational |
|
647 |
|
648 CDbTable::TValid::TValid(CDbTable& aTable) |
|
649 :iTable(aTable) |
|
650 { |
|
651 __ASSERT(aTable.IsActive()); |
|
652 iRollback.Construct(aTable.Database().Transaction().RollbackGeneration()); |
|
653 } |
|
654 |
|
655 TBool CDbTable::TValid::Reset() |
|
656 { |
|
657 TBool b=Table().IsActive(); |
|
658 if (b) |
|
659 iRollback.Mark(); |
|
660 return b; |
|
661 } |
|
662 |
|
663 void CDbTable::TValid::CheckL() const |
|
664 { |
|
665 CDbTableDatabase* d=Table().iDatabase; |
|
666 if (!d) |
|
667 __LEAVE(KErrDisconnected); |
|
668 else |
|
669 d->Transaction().ReadyL(); |
|
670 if (iRollback.Changed()) |
|
671 __LEAVE(KErrNotReady); |
|
672 } |