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