|
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 // Class CDbTableCursor::HColumns |
|
19 |
|
20 class CDbTableCursor::HColumns |
|
21 { |
|
22 public: |
|
23 static HColumns* NewL(const CDbDataSource* aSource); |
|
24 inline TInt Count() const |
|
25 {return iCount;} |
|
26 inline TDbColType Type(TDbColNo aCol) const |
|
27 {__DEBUG(Check(aCol));return TDbColType(iType[aCol-1]);} |
|
28 void Check(TDbColNo aCol) const; |
|
29 private: |
|
30 TInt iCount; |
|
31 TUint8 iType[1]; |
|
32 }; |
|
33 |
|
34 CDbTableCursor::HColumns* CDbTableCursor::HColumns::NewL(const CDbDataSource* aSource) |
|
35 { |
|
36 TInt count=aSource->ColumnCount(); |
|
37 HColumns* self=(HColumns*)User::AllocL(_FOFF(HColumns,iType[count])); |
|
38 self->iCount=count; |
|
39 TUint8* pp=&self->iType[0]; |
|
40 for (TDbColNo ii=1;ii<=count;++ii,++pp) |
|
41 *pp=aSource->ColumnDef(ii).iType; |
|
42 return self; |
|
43 } |
|
44 |
|
45 void CDbTableCursor::HColumns::Check(TDbColNo aColNo) const |
|
46 { |
|
47 __ASSERT_ALWAYS(TUint(aColNo-1)<TUint(iCount),Panic(EDbInvalidColumn)); |
|
48 } |
|
49 |
|
50 // Class CDbTableCursor::CConstraint |
|
51 |
|
52 NONSHARABLE_CLASS(CDbTableCursor::CConstraint) : public CDbRowConstraint |
|
53 { |
|
54 public: |
|
55 CConstraint(CDbTableCursor& aCursor,CSqlSearchCondition* aSearchCondition,TDbTextComparison aComparison); |
|
56 ~CConstraint(); |
|
57 // |
|
58 inline TBool Check(CDbTableCursor& aCursor) const; |
|
59 inline TBool MatchL() const; |
|
60 private: |
|
61 CDbTableCursor& iCursor; |
|
62 CSqlSearchCondition* iSearchCondition; |
|
63 const TTextOps& iTextOps; |
|
64 }; |
|
65 |
|
66 CDbTableCursor::CConstraint::CConstraint(CDbTableCursor& aCursor,CSqlSearchCondition* aSearchCondition,TDbTextComparison aComparison) |
|
67 : iCursor(aCursor), iSearchCondition(aSearchCondition), iTextOps(TTextOps::Ops(aComparison)) |
|
68 {} |
|
69 |
|
70 CDbTableCursor::CConstraint::~CConstraint() |
|
71 { |
|
72 delete iSearchCondition; |
|
73 } |
|
74 |
|
75 inline TBool CDbTableCursor::CConstraint::Check(CDbTableCursor& aCursor) const |
|
76 {return &iCursor==&aCursor;} |
|
77 inline TBool CDbTableCursor::CConstraint::MatchL() const |
|
78 {return iSearchCondition->EvaluateL(iTextOps);} |
|
79 |
|
80 // Class CDbTableCursor |
|
81 |
|
82 inline void CDbTableCursor::CheckStateL() const |
|
83 {iValid.CheckL();} |
|
84 inline RDbTransaction& CDbTableCursor::Transaction() |
|
85 {__ASSERT(iValid);return iValid.Transaction();} |
|
86 inline TBool CDbTableCursor::InUpdate() const |
|
87 {return iFlags&(EUpdating|EInserting);} |
|
88 |
|
89 CDbTableCursor::CDbTableCursor(RDbAccessPlan& aPlan,RDbRowSet::TAccess aAccess) |
|
90 : iState(ERowBeginning),iValid(aPlan.Table()),iDataSource(aPlan.Adopt()) |
|
91 { |
|
92 switch (aAccess) |
|
93 { |
|
94 default: |
|
95 __ASSERT(0); |
|
96 case RDbRowSet::EUpdatable: |
|
97 iFlags=EUpdatable|EReadable; |
|
98 break; |
|
99 case RDbRowSet::EReadOnly: |
|
100 iFlags=EReadable; |
|
101 break; |
|
102 case RDbRowSet::EInsertOnly: |
|
103 iFlags=EUpdatable; |
|
104 break; |
|
105 } |
|
106 } |
|
107 |
|
108 CDbTableCursor::~CDbTableCursor() |
|
109 { |
|
110 Cancel(); |
|
111 delete iDataSource; |
|
112 delete iColumns; |
|
113 } |
|
114 |
|
115 CDbTableCursor* CDbTableCursor::NewL(RDbAccessPlan& aPlan,RDbRowSet::TAccess aAccess) |
|
116 { |
|
117 CDbTableCursor* self=new(ELeave) CDbTableCursor(aPlan,aAccess); |
|
118 CleanupStack::PushL(self); |
|
119 self->iColumns=HColumns::NewL(self->iDataSource); |
|
120 self->Reset(); |
|
121 CleanupStack::Pop(); |
|
122 return self; |
|
123 } |
|
124 |
|
125 TDbColType CDbTableCursor::Type(TDbColNo aCol) const |
|
126 { |
|
127 iColumns->Check(aCol); |
|
128 return iColumns->Type(aCol); |
|
129 } |
|
130 |
|
131 void CDbTableCursor::Reset() |
|
132 // |
|
133 // Reset the cursor for re-evaluation |
|
134 // |
|
135 { |
|
136 AssertNotInUpdate(); |
|
137 if (iValid.Reset()) |
|
138 { |
|
139 iDataSource->Reset(); |
|
140 iState=ERowBeginning; |
|
141 } |
|
142 } |
|
143 |
|
144 TBool CDbTableCursor::EvaluateL() |
|
145 // |
|
146 // Do a unit of evaluation work |
|
147 // |
|
148 { |
|
149 AssertNotInUpdate(); |
|
150 CheckStateL(); |
|
151 TInt work=256; |
|
152 TBool atRow=EFalse; |
|
153 TBool more=iDataSource->EvaluateL(work,iRecord,atRow); |
|
154 if (atRow) |
|
155 { // evaluation results in a record appearing under the cursor |
|
156 switch (iState) |
|
157 { |
|
158 case ERowEnd: |
|
159 case ERowBeginning: |
|
160 iState=ERowOK; |
|
161 break; |
|
162 case ERowDeletedAtEnd: |
|
163 iState=ERowDeletedAtNext; |
|
164 break; |
|
165 default: |
|
166 break; |
|
167 } |
|
168 } |
|
169 return more?1:0; |
|
170 } |
|
171 |
|
172 void CDbTableCursor::Evaluate(TRequestStatus& aStatus) |
|
173 // |
|
174 // Asynchronous evaluation: invoke synchronous version |
|
175 // |
|
176 { |
|
177 TRequestStatus* pStatus=&aStatus; |
|
178 User::RequestComplete(pStatus,CDbCursor::Evaluate()); |
|
179 } |
|
180 |
|
181 TBool CDbTableCursor::Unevaluated() |
|
182 // |
|
183 // Report if there is evaluation to be done |
|
184 // |
|
185 { |
|
186 return iValid ? iDataSource->Unevaluated() : EFalse; |
|
187 } |
|
188 |
|
189 TInt CDbTableCursor::CountL(RDbRowSet::TAccuracy aAccuracy) |
|
190 { |
|
191 AssertNotInUpdate(); |
|
192 CheckReadL(); |
|
193 TInt count=iDataSource->CountL(); |
|
194 return (count==KDbUndefinedCount && aAccuracy==RDbRowSet::EEnsure) |
|
195 ? CDbCursor::CountL(aAccuracy) |
|
196 : count; |
|
197 } |
|
198 |
|
199 TBool CDbTableCursor::AtBeginning() |
|
200 { |
|
201 return iState==ERowBeginning; |
|
202 } |
|
203 |
|
204 TBool CDbTableCursor::AtEnd() |
|
205 { |
|
206 return iState==ERowEnd; |
|
207 } |
|
208 |
|
209 TBool CDbTableCursor::AtRow() |
|
210 { |
|
211 return (iState==ERowOK||(iFlags&EInserting)); |
|
212 } |
|
213 |
|
214 TBool CDbTableCursor::GotoL(RDbRowSet::TPosition aPosition) |
|
215 // |
|
216 // Move the cursor in the requested direction |
|
217 // return whether we are at a row or not |
|
218 // |
|
219 { |
|
220 AssertNotInUpdate(); |
|
221 CheckReadL(); |
|
222 iFlags&=~ERead; |
|
223 switch (aPosition) |
|
224 { |
|
225 default: |
|
226 __ASSERT(0); |
|
227 case RDbRowSet::EFirst: |
|
228 case RDbRowSet::ELast: |
|
229 break; |
|
230 case RDbRowSet::ENext: |
|
231 switch (iState) |
|
232 { |
|
233 default: |
|
234 __ASSERT(0); |
|
235 case ERowInLimbo: // in between previous and next, must evaluate |
|
236 case ERowOK: |
|
237 break; |
|
238 case ERowBeginning: // goto first record |
|
239 aPosition=RDbRowSet::EFirst; |
|
240 break; |
|
241 case ERowEnd: |
|
242 case ERowInvalid: |
|
243 Panic(EDbInvalidRow); |
|
244 break; |
|
245 case ERowDeletedAtNext: // already have the id |
|
246 if (iDataSource->GotoL(iRecord)) |
|
247 { // and the record is still there |
|
248 iState=ERowOK; |
|
249 return ETrue; |
|
250 } |
|
251 break; |
|
252 case ERowDeletedAtEnd: // straight to end |
|
253 iState=ERowEnd; |
|
254 return EFalse; |
|
255 } |
|
256 break; |
|
257 case RDbRowSet::EPrevious: |
|
258 switch (iState) |
|
259 { |
|
260 default: |
|
261 __ASSERT(0); |
|
262 case ERowOK: |
|
263 case ERowDeletedAtNext: // goto previous will do what we want |
|
264 case ERowInLimbo: // in between previous and next, must evaluate |
|
265 break; |
|
266 case ERowEnd: // goto last row |
|
267 case ERowDeletedAtEnd: // previous is last row |
|
268 aPosition=RDbRowSet::ELast; |
|
269 break; |
|
270 case ERowBeginning: |
|
271 case ERowInvalid: |
|
272 Panic(EDbInvalidRow); |
|
273 break; |
|
274 } |
|
275 break; |
|
276 case RDbRowSet::EBeginning: |
|
277 iState=ERowBeginning; |
|
278 return EFalse; |
|
279 case RDbRowSet::EEnd: |
|
280 iState=ERowEnd; |
|
281 return EFalse; |
|
282 } |
|
283 iState=ERowInvalid; |
|
284 switch (iDataSource->GotoL(TDbPosition(aPosition),iRecord)) |
|
285 { |
|
286 default: |
|
287 __ASSERT(0); |
|
288 case CDbDataSource::ESynchFailure: |
|
289 __LEAVE(KErrNotReady); |
|
290 case CDbDataSource::ESuccess: |
|
291 iState=ERowOK; |
|
292 return ETrue; |
|
293 case CDbDataSource::ENoRow: |
|
294 iState=TUint8(aPosition<RDbRowSet::EPrevious ? ERowEnd : ERowBeginning); |
|
295 return EFalse; |
|
296 } |
|
297 } |
|
298 |
|
299 void CDbTableCursor::Bookmark(TDbBookmark::TMark& aMark) |
|
300 // |
|
301 // Create a bookmark for the current cursor state |
|
302 // Can bookmark ANY position. |
|
303 // |
|
304 { |
|
305 AssertNotInUpdate(); |
|
306 aMark.iMark[0]=iState; |
|
307 aMark.iMark[1]=iRecord.Value(); |
|
308 } |
|
309 |
|
310 void CDbTableCursor::GotoL(const TDbBookmark::TMark& aMark) |
|
311 // |
|
312 // Reestablish the cursor state from a bookmark (if possible) |
|
313 // |
|
314 { |
|
315 AssertNotInUpdate(); |
|
316 CheckStateL(); |
|
317 iState=ERowInvalid; |
|
318 iRecord=aMark.iMark[1]; |
|
319 TState state=TState(aMark.iMark[0]); |
|
320 switch (state) |
|
321 { |
|
322 default: |
|
323 Panic(EDbInvalidBookmark); |
|
324 case ERowBeginning: |
|
325 case ERowEnd: |
|
326 case ERowDeletedAtEnd: |
|
327 case ERowInLimbo: |
|
328 case ERowInvalid: |
|
329 break; |
|
330 case ERowDeletedAtNext: |
|
331 case ERowOK: |
|
332 if (!iDataSource->GotoL(iRecord)) |
|
333 __LEAVE(KErrNotFound); |
|
334 break; |
|
335 } |
|
336 iState=TUint8(state); |
|
337 } |
|
338 |
|
339 void CDbTableCursor::GetL() |
|
340 // |
|
341 // read the current row into the row buffer for access |
|
342 // |
|
343 { |
|
344 AssertValidRow(); |
|
345 CheckStateL(); |
|
346 iFlags&=~ERead; |
|
347 iDataSource->ReadRowL(iRecord); |
|
348 iFlags|=ERead; |
|
349 } |
|
350 |
|
351 void CDbTableCursor::InsertL(TInsert aClearRow) |
|
352 // |
|
353 // Insert a new row. If aCLearRow==aCopy, then copy the current row |
|
354 // |
|
355 { |
|
356 AssertNotInUpdate(); |
|
357 CheckUpdateL(); |
|
358 Transaction().DMLPrepareL(*this); |
|
359 if (aClearRow==ECopy) |
|
360 { |
|
361 AssertValidRow(); |
|
362 iFlags&=~ERead; // in case of failure in NewRowL |
|
363 iDataSource->NewRowL(iRecord); |
|
364 } |
|
365 else |
|
366 iDataSource->NewRowL(KDbNullRecordId); |
|
367 iFlags|=EInserting|ERead; |
|
368 Transaction().DMLBegin(); |
|
369 } |
|
370 |
|
371 void CDbTableCursor::UpdateL() |
|
372 { |
|
373 CheckUpdateL(); |
|
374 Transaction().DMLPrepareL(*this); |
|
375 GetL(); |
|
376 iFlags|=EUpdating; |
|
377 Transaction().DMLBegin(); |
|
378 } |
|
379 |
|
380 void CDbTableCursor::Cancel() |
|
381 { |
|
382 AssertNoStreams(); |
|
383 if (InUpdate()) |
|
384 { |
|
385 RDbTransaction& t=Transaction(); |
|
386 if (iFlags&EDirty) |
|
387 t.DMLTouch(); // we've mucked about with BLOBs, so force true roll-back |
|
388 t.DMLRollback(); |
|
389 if (iFlags&EUpdating) |
|
390 { |
|
391 TRAP_IGNORE(iDataSource->ReadRowL(KDbNullRecordId)); // row buffer contains NULL row (cannot fail) |
|
392 } |
|
393 iFlags&=(EUpdatable|EReadable); |
|
394 } |
|
395 } |
|
396 |
|
397 void CDbTableCursor::PutL() |
|
398 { |
|
399 AssertInUpdate(); |
|
400 CheckStateL(); |
|
401 CDbDataSource::TWrite mode=iFlags&EUpdating ? CDbDataSource::EReplace : CDbDataSource::EAppend; |
|
402 iDataSource->PrepareToWriteRowL(mode); |
|
403 RDbTransaction& t=Transaction(); |
|
404 t.DMLTouch(); |
|
405 iFlags&=~EDirty; |
|
406 iRecord=iDataSource->WriteRowL(mode,iFlags&EReadable ? CDbDataSource::ESynch : CDbDataSource::ENoSynch); |
|
407 t.DMLCommitL(); |
|
408 if ((iFlags&(EInserting|EReadable))==(EInserting|EReadable)) |
|
409 iState=ERowOK; |
|
410 iFlags&=(EUpdatable|EReadable|ERead); |
|
411 } |
|
412 |
|
413 void CDbTableCursor::DeleteL() |
|
414 { |
|
415 AssertValidRow(); |
|
416 CheckUpdateL(); |
|
417 RDbTransaction& t=Transaction(); |
|
418 t.DMLPrepareL(*this); |
|
419 t.DMLBeginLC(); |
|
420 CDbDataSource::TDelete del=iDataSource->DeleteRowL(iRecord); |
|
421 t.DMLCommitL(); |
|
422 CleanupStack::Pop(); // rollback not required |
|
423 iState=TUint8(del+ERowDeletedAtNext); |
|
424 } |
|
425 |
|
426 TInt CDbTableCursor::ColumnCount() |
|
427 { |
|
428 return iColumns->Count(); |
|
429 } |
|
430 |
|
431 void CDbTableCursor::ColumnDef(TDbCol& aCol,TDbColNo aColNo) |
|
432 { |
|
433 iColumns->Check(aColNo); |
|
434 if (iValid) |
|
435 iDataSource->ColumnDef(aColNo).AsTDbCol(aCol); |
|
436 } |
|
437 |
|
438 TDbColType CDbTableCursor::ColumnType(TDbColNo aCol) |
|
439 { |
|
440 return Type(aCol); |
|
441 } |
|
442 |
|
443 void CDbTableCursor::ReplaceBlobL(TDbColumn& aCol) |
|
444 { |
|
445 CheckStateL(); |
|
446 const TDbBlob& blob=TDbColumnC(aCol).Blob(); |
|
447 if (!blob.IsInline()) |
|
448 { |
|
449 iFlags|=EDirty; |
|
450 BlobsL().DeleteL(blob.Id()); |
|
451 } |
|
452 } |
|
453 |
|
454 void CDbTableCursor::AddBlobSource() |
|
455 // |
|
456 // Increment the source count and take a read-lock on the database |
|
457 // |
|
458 { |
|
459 AddSource(); |
|
460 Transaction().ReadBegin(*this); |
|
461 } |
|
462 |
|
463 void CDbTableCursor::ReleaseBlobSource() |
|
464 // |
|
465 // Decrement the source count and release the read-lock on the database |
|
466 // |
|
467 { |
|
468 ReleaseSource(); |
|
469 Transaction().ReadRelease(*this); |
|
470 } |
|
471 |
|
472 MStreamBuf* CDbTableCursor::ColumnSourceL(TDbColNo aCol) |
|
473 { |
|
474 TDbColumnC col(ColumnC(aCol)); |
|
475 if ((iFlags&EWriteBuf) || iReadBuf==EMaxReadBuf) |
|
476 __LEAVE(KErrInUse); // only allow 1-write or 255-read streambufs |
|
477 TDbColType type=iColumns->Type(aCol); |
|
478 if (!TDbCol::IsLong(type)) |
|
479 return HMemBuf::NewL(*this,col.PtrC8()); |
|
480 // blobs |
|
481 const TDbBlob& blob=col.Blob(); |
|
482 if (blob.IsInline()) |
|
483 return HMemBuf::NewL(*this,blob.PtrC8()); |
|
484 // if small enough, pull the blob data through immediately and avoid locking the database |
|
485 if (blob.Size()<=HHeapBuf::EMaxBlobBuffer) |
|
486 return HHeapBuf::NewL(*this,blob,type); |
|
487 // |
|
488 CheckStateL(); |
|
489 Transaction().ReadPrepareL(*this); |
|
490 HReadBuf* buf=HReadBuf::NewLC(*this); |
|
491 buf->Set(BlobsL().ReadL(blob.Id(),type)); |
|
492 CleanupStack::Pop(); |
|
493 return buf; |
|
494 } |
|
495 |
|
496 MStreamBuf* CDbTableCursor::ColumnSinkL(TDbColNo aCol) |
|
497 { |
|
498 TDbColType type=Type(aCol); |
|
499 __ASSERT_ALWAYS(TDbCol::IsLong(type),Panic(EDbWrongType)); |
|
500 TDbColumn col=Column(aCol); |
|
501 ReplaceBlobL(col); |
|
502 iFlags|=EDirty; |
|
503 return HWriteBuf::NewL(*this,col,type); |
|
504 } |
|
505 |
|
506 void CDbTableCursor::SetNullL(TDbColNo aCol) |
|
507 // |
|
508 // Make the column Null |
|
509 // |
|
510 { |
|
511 TDbColumn col=Column(aCol); |
|
512 if (TDbCol::IsLong(Type(aCol))) |
|
513 ReplaceBlobL(col); |
|
514 col.SetNull(); |
|
515 } |
|
516 |
|
517 TInt CDbTableCursor::ColumnSize(TDbColNo aCol) |
|
518 { |
|
519 TDbColumnC col(ColumnC(aCol)); |
|
520 return TDbCol::IsLong(Type(aCol)) ? col.Blob().Size() : col.Size(); |
|
521 } |
|
522 |
|
523 RDbRow* CDbTableCursor::RowBuffer() |
|
524 // |
|
525 // Invoked by the server for whole-row access where possible |
|
526 // |
|
527 { |
|
528 __ASSERT(iFlags&ERead); |
|
529 return iDataSource->RowBuffer(); |
|
530 } |
|
531 |
|
532 TDbColumnC CDbTableCursor::ColumnC(TDbColNo aCol) |
|
533 // |
|
534 // check row is valid for extraction |
|
535 // |
|
536 { |
|
537 __ASSERT_ALWAYS(iFlags&ERead,Panic(EDbRowNotRead)); |
|
538 return iDataSource->Column(aCol); |
|
539 } |
|
540 |
|
541 TDbColumn CDbTableCursor::Column(TDbColNo aCol) |
|
542 // |
|
543 // check row is valid for writing |
|
544 // |
|
545 { |
|
546 AssertInUpdate(); |
|
547 return iDataSource->Column(aCol); |
|
548 } |
|
549 |
|
550 void CDbTableCursor::SetIndexL(const TDesC* anIndex) |
|
551 { |
|
552 AssertNotInUpdate(); |
|
553 CheckReadL(); |
|
554 iDataSource->SetIndexL(anIndex); |
|
555 iState=ERowBeginning; |
|
556 } |
|
557 |
|
558 TBool CDbTableCursor::SeekL(const TDbLookupKey& aKey,RDbTable::TComparison aComparison) |
|
559 { |
|
560 AssertNotInUpdate(); |
|
561 CheckReadL(); |
|
562 iFlags&=~ERead; |
|
563 iState=ERowInvalid; |
|
564 TBool atrow=iDataSource->SeekL(aKey,aComparison,iRecord); |
|
565 if (atrow) |
|
566 iState=ERowOK; |
|
567 return atrow; |
|
568 } |
|
569 |
|
570 CDbRowConstraint* CDbTableCursor::OpenConstraintL(const TDbQuery& aCriteria) |
|
571 // |
|
572 // Construct a constraint for this rowset |
|
573 // |
|
574 { |
|
575 CSqlSearchCondition* sc=iDataSource->ParseConstraintLC(aCriteria.Query()); |
|
576 CDbRowConstraint* constraint=new(ELeave) CConstraint(*this,sc,aCriteria.Comparison()); |
|
577 CleanupStack::Pop(); |
|
578 return constraint; |
|
579 } |
|
580 |
|
581 TBool CDbTableCursor::MatchL(CDbRowConstraint& aConstraint) |
|
582 { |
|
583 CConstraint& c=STATIC_CAST(CConstraint&,aConstraint); |
|
584 __ASSERT_ALWAYS(c.Check(*this),Panic(EDbRowSetConstraintMismatch)); |
|
585 GetL(); |
|
586 return c.MatchL(); |
|
587 } |
|
588 |
|
589 void CDbTableCursor::CheckReadL() const |
|
590 // |
|
591 // Ensure we are a readable cursor |
|
592 // |
|
593 { |
|
594 CheckStateL(); |
|
595 if ((iFlags&EReadable)==0) |
|
596 __LEAVE(KErrWrite); |
|
597 } |
|
598 |
|
599 void CDbTableCursor::CheckUpdateL() const |
|
600 // |
|
601 // Ensure we are a writable cursor |
|
602 // |
|
603 { |
|
604 CheckStateL(); |
|
605 if ((iFlags&EUpdatable)==0) |
|
606 __LEAVE(KErrWrite); |
|
607 } |
|
608 |
|
609 void CDbTableCursor::AssertNoStreams() const |
|
610 { |
|
611 __ASSERT_ALWAYS((iFlags&EWriteBuf)==0 && iReadBuf==0,Panic(EDbStreamOpen)); |
|
612 } |
|
613 |
|
614 void CDbTableCursor::AssertNotInUpdate() const |
|
615 { |
|
616 __ASSERT_ALWAYS(!InUpdate(),Panic(EDbInUpdate)); |
|
617 AssertNoStreams(); |
|
618 } |
|
619 |
|
620 void CDbTableCursor::AssertInUpdate() const |
|
621 { |
|
622 __ASSERT_ALWAYS(InUpdate(),Panic(EDbNotInUpdate)); |
|
623 AssertNoStreams(); |
|
624 } |
|
625 |
|
626 void CDbTableCursor::AssertValidRow() const |
|
627 { |
|
628 AssertNotInUpdate(); |
|
629 __ASSERT_ALWAYS(iState==ERowOK||(iFlags&EInserting),Panic(EDbInvalidRow)); |
|
630 } |
|
631 |