|
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 "D32COMP.H" |
|
18 #include <d32dbmsconstants.h> |
|
19 |
|
20 // Class RDbAccessPlan::TPlan |
|
21 |
|
22 TInt RDbAccessPlan::TPlan::OrderByPlan(const TPlan& aLeft,const TPlan& aRight) |
|
23 { |
|
24 TUint lpos=aLeft.Type(); |
|
25 TUint rpos=aRight.Type(); |
|
26 __ASSERT(lpos!=0 && rpos!=0 ); // should be no table iterators |
|
27 return lpos-rpos; |
|
28 } |
|
29 |
|
30 RDbAccessPlan::TPlan::TType RDbAccessPlan::TPlan::Type() const |
|
31 // |
|
32 // flag values: 0=A, 1=C, 2=B, 3=D, 8=E/F, 10=G/H, 16=M/N, 18=S/T, 20=I/J, 21=K/L, 22=O/P, 23=Q/R |
|
33 // This determines order of plans |
|
34 // |
|
35 { |
|
36 static const TUint KPosition[]={EPlanA,EPlanC,EPlanB,EPlanD,0,0,0,0,EPlanEF,0,EPlanGH,0,0,0,0,0,EPlanMN, |
|
37 0,EPlanST,0,EPlanIJ,EPlanKL,EPlanOP,EPlanQR}; |
|
38 __ASSERT_ALWAYS(((iFlags&EMask) < (sizeof(KPosition)/sizeof(KPosition[0]))), User::Invariant()); |
|
39 return TType(KPosition[iFlags&EMask]); |
|
40 } |
|
41 |
|
42 // Class RDbAccessPlan::TBounds |
|
43 |
|
44 RDbAccessPlan::TBounds::TBounds(const TPlan& aPlan) |
|
45 : iLowerPred(aPlan.iLower),iUpperPred(aPlan.iUpper),iLower(0),iUpper(0),iInclusion(0) |
|
46 { |
|
47 SetLowerBounds(); |
|
48 SetUpperBounds(); |
|
49 if (aPlan.iIndex->Key()[0].iOrder==TDbKeyCol::EDesc) |
|
50 { |
|
51 TDbLookupKey* t=iLower; |
|
52 iLower=iUpper; |
|
53 iUpper=t; |
|
54 iInclusion=(iInclusion>>1)|(iInclusion<<1); |
|
55 } |
|
56 } |
|
57 |
|
58 void RDbAccessPlan::TBounds::GetLookupKey(const CSqlCompPredicate& aCompPredicate,TDbLookupKey& aLookup) |
|
59 { |
|
60 const RSqlLiteral& value=aCompPredicate.Value(); |
|
61 switch (aCompPredicate.ColType()) |
|
62 { |
|
63 default: |
|
64 __ASSERT(0); |
|
65 case EDbColBit: |
|
66 case EDbColInt8: |
|
67 case EDbColUint8: |
|
68 case EDbColInt16: |
|
69 case EDbColUint16: |
|
70 case EDbColInt32: |
|
71 case EDbColUint32: |
|
72 case EDbColInt64: |
|
73 aLookup.Add(value.Int64()); |
|
74 break; |
|
75 case EDbColReal32: |
|
76 case EDbColReal64: |
|
77 aLookup.Add(value.Real64()); |
|
78 break; |
|
79 case EDbColDateTime: |
|
80 aLookup.Add(value.Time()); |
|
81 break; |
|
82 case EDbColText8: |
|
83 case EDbColLongText8: |
|
84 aLookup.Add(value.Text8()); |
|
85 break; |
|
86 case EDbColText16: |
|
87 case EDbColLongText16: |
|
88 aLookup.Add(value.Text16()); |
|
89 break; |
|
90 } |
|
91 } |
|
92 |
|
93 void RDbAccessPlan::TBounds::SetLowerBounds() |
|
94 { |
|
95 if (!iLowerPred) // iLower already set to 0 |
|
96 return; |
|
97 GetLookupKey(*iLowerPred,iLowerKey); |
|
98 switch (iLowerPred->NodeType()) |
|
99 { |
|
100 default: |
|
101 __ASSERT(0); |
|
102 case CSqlSearchCondition::ELessEqual: |
|
103 case CSqlSearchCondition::ELess: |
|
104 iLower=0; |
|
105 break; |
|
106 case CSqlSearchCondition::EEqual: |
|
107 case CSqlSearchCondition::EGreaterEqual: |
|
108 iInclusion|=CDbRecordIndex::EIncludeLower; |
|
109 case CSqlSearchCondition::EGreater: |
|
110 iLower=&iLowerKey; |
|
111 break; |
|
112 } |
|
113 } |
|
114 |
|
115 void RDbAccessPlan::TBounds::SetUpperBounds() |
|
116 { |
|
117 if (!iUpperPred) |
|
118 return; |
|
119 GetLookupKey(*iUpperPred,iUpperKey); |
|
120 switch (iUpperPred->NodeType()) |
|
121 { |
|
122 default: |
|
123 __ASSERT(0); |
|
124 case CSqlSearchCondition::EGreaterEqual: |
|
125 case CSqlSearchCondition::EGreater: |
|
126 iUpper=0; |
|
127 break; |
|
128 case CSqlSearchCondition::EEqual: |
|
129 case CSqlSearchCondition::ELessEqual: |
|
130 iInclusion|=CDbRecordIndex::EIncludeUpper; |
|
131 case CSqlSearchCondition::ELess: |
|
132 iUpper=&iUpperKey; |
|
133 break; |
|
134 } |
|
135 } |
|
136 |
|
137 // Class RDbAccessPlan::CDbCompPredicateList |
|
138 |
|
139 RDbAccessPlan::CDbCompPredicateList* RDbAccessPlan::CDbCompPredicateList::NewLC(CSqlQuery& aQuery,TDbTextComparison aComparison,const CDbTableDef& aTableDef) |
|
140 { |
|
141 CDbCompPredicateList* self=new(ELeave) CDbCompPredicateList(aTableDef,aComparison); |
|
142 CleanupStack::PushL(self); |
|
143 CSqlSearchCondition& sc=aQuery.SearchCondition(); |
|
144 self->ConstructL(sc); |
|
145 return self; |
|
146 } |
|
147 |
|
148 void RDbAccessPlan::CDbCompPredicateList::ConstructL(CSqlSearchCondition& aSearchCondition) |
|
149 // |
|
150 // fill the list with valid comp pred's |
|
151 // |
|
152 { |
|
153 TUint type=Type(aSearchCondition.NodeType()); |
|
154 if (type&ECompPred) |
|
155 { |
|
156 CSqlCompPredicate* cp=aSearchCondition.CompPredicate(); |
|
157 const TDesC& colName=cp->ColumnName(); |
|
158 if (IsIndexed(colName)) |
|
159 AppendL(cp); |
|
160 else |
|
161 iRestriction=ETrue; |
|
162 } |
|
163 else if (type&EAnd) |
|
164 { |
|
165 CSqlMultiNode* multiNode=aSearchCondition.MultiNode(); |
|
166 for (TInt ii=multiNode->Count();ii--;) |
|
167 { |
|
168 CSqlSearchCondition* node=multiNode->SubNode(ii); |
|
169 ConstructL(*node); |
|
170 } |
|
171 } |
|
172 else |
|
173 iRestriction=ETrue; |
|
174 } |
|
175 |
|
176 TUint RDbAccessPlan::CDbCompPredicateList::Type(CSqlSearchCondition::TType aType) const |
|
177 // |
|
178 // converts CSqlSearchCondition::TType into flag |
|
179 // |
|
180 { |
|
181 switch (aType) |
|
182 { |
|
183 case CSqlSearchCondition::EAnd: |
|
184 return EAnd; |
|
185 case CSqlSearchCondition::ELess: |
|
186 return ELess; |
|
187 case CSqlSearchCondition::ELessEqual: |
|
188 return ELessEqual; |
|
189 case CSqlSearchCondition::EEqual: |
|
190 return EEqual; |
|
191 case CSqlSearchCondition::EGreaterEqual: |
|
192 return EGreaterEqual; |
|
193 case CSqlSearchCondition::EGreater: |
|
194 return EGreater; |
|
195 default: |
|
196 return ENone; |
|
197 } |
|
198 } |
|
199 |
|
200 TBool RDbAccessPlan::CDbCompPredicateList::IsIndexed(const TDesC& aColumnName) |
|
201 // |
|
202 // Checks if aColumnName is indexed. If its a text column the comparison method should be the same |
|
203 // |
|
204 { |
|
205 const CDbTableIndexDef* key=iTableDef.Key(aColumnName); |
|
206 if (!key) |
|
207 return EFalse; |
|
208 const TDbColumnDef* colDef=NULL; |
|
209 TRAPD(errCode, colDef=iTableDef.Columns().ColumnL(aColumnName)); |
|
210 if(errCode != KErrNone) |
|
211 return EFalse; |
|
212 if (colDef->Type()>EDbColDateTime && key->Key().Comparison()!=iComparison) |
|
213 return EFalse; |
|
214 return ETrue; |
|
215 } |
|
216 |
|
217 CSqlCompPredicate* RDbAccessPlan::CDbCompPredicateList::CompPredicate(TDbColNo aColNo,TUint aType) |
|
218 // |
|
219 // Returns first CompPredicate found in the list with required type & col no, and removes from list |
|
220 // |
|
221 { |
|
222 for (TInt ii=Count();ii--;) |
|
223 { |
|
224 CSqlCompPredicate* cp=At(ii); |
|
225 TUint type=Type(cp->NodeType()); |
|
226 TDbColNo colNo=cp->ColNo(); |
|
227 if (!type&aType || aColNo!=colNo) |
|
228 continue; |
|
229 Delete(ii); |
|
230 return cp; |
|
231 } |
|
232 return 0; |
|
233 } |
|
234 |
|
235 // class Validate |
|
236 |
|
237 void Validate::NameL(const TDesC& aName) |
|
238 { |
|
239 if (aName.Length()<=KDbMaxName) |
|
240 { |
|
241 TLex lex(aName); |
|
242 if (!lex.Eos() && lex.Get().IsAlpha()) |
|
243 { |
|
244 TChar c; |
|
245 do |
|
246 { |
|
247 if (lex.Eos()) |
|
248 return; |
|
249 c=lex.Get(); |
|
250 } while (c.IsAlphaDigit()||c=='_'); |
|
251 } |
|
252 } |
|
253 __LEAVE(KErrBadName); |
|
254 } |
|
255 |
|
256 void Validate::UniqueNameL(TDesC const** aNames,TInt aCount,const TDesC& aName) |
|
257 // |
|
258 // Ensure that aName is not a duplicate of any of aNames, and add |
|
259 // the new name to the collection. Binary search is used for speed |
|
260 // |
|
261 { |
|
262 TInt left=0; |
|
263 TInt right=aCount; |
|
264 while (left<right) |
|
265 { |
|
266 TInt mid=(left+right)>>1; |
|
267 TInt c=aNames[mid]->CompareF(aName); |
|
268 if (c<0) |
|
269 left=mid+1; |
|
270 else if (c>0) |
|
271 right=mid; |
|
272 else |
|
273 __LEAVE(KErrArgument); |
|
274 } |
|
275 Mem::Move(aNames+left+1,aNames+left,(aCount-left)*sizeof(TDesC const*)); |
|
276 aNames[left]=&aName; |
|
277 } |
|
278 |
|
279 void Validate::ColSetL(const CDbColSet& aColSet) |
|
280 { |
|
281 TDbColSetIter iter(aColSet); |
|
282 if (!iter) |
|
283 __LEAVE(KErrArgument); |
|
284 TDesC const** names=(TDesC const**)User::AllocLC(aColSet.Count()*sizeof(TDesC const*)); |
|
285 do |
|
286 { |
|
287 const TDbCol& col=*iter; |
|
288 NameL(col.iName); |
|
289 UniqueNameL(names,iter.Col()-1,col.iName); |
|
290 TInt type=TInt(col.iType); |
|
291 if (type<TInt(EDbColBit)||type>TInt(EDbColLongBinary)) |
|
292 __LEAVE(KErrNotSupported); |
|
293 else if (col.iMaxLength<1&&col.iMaxLength!=KDbUndefinedLength) |
|
294 __LEAVE(KErrArgument); |
|
295 else if (col.iAttributes&~(TDbCol::ENotNull|TDbCol::EAutoIncrement)) |
|
296 __LEAVE(KErrNotSupported); // unknown attributes |
|
297 else if (type>EDbColUint32 && col.iAttributes&TDbCol::EAutoIncrement) |
|
298 __LEAVE(KErrArgument); // auto increment on non-integral type |
|
299 } while (++iter); |
|
300 CleanupStack::PopAndDestroy(); |
|
301 } |
|
302 |
|
303 void Validate::KeyL(const CDbKey& aKey,const HDbColumnSet& aColumns) |
|
304 // |
|
305 // Check that the key is valid for the table |
|
306 // |
|
307 { |
|
308 TInt max=aKey.Count()-1; |
|
309 if (max<0) |
|
310 __LEAVE(KErrArgument); |
|
311 for (TInt ii=0;ii<=max;++ii) |
|
312 { |
|
313 const TDbKeyCol& kCol=aKey[ii]; |
|
314 HDbColumnSet::TIteratorC col=aColumns.ColumnL(kCol.iName); |
|
315 if (col==NULL) |
|
316 __LEAVE(KErrNotFound); |
|
317 TInt len=kCol.iLength; |
|
318 if (len!=KDbUndefinedLength) |
|
319 { |
|
320 if (col->iType<=EDbColDateTime) |
|
321 __LEAVE(KErrArgument); |
|
322 TInt cLen=col->iMaxLength; |
|
323 if (ii<max) |
|
324 { |
|
325 if (len!=cLen) |
|
326 __LEAVE(KErrNotSupported); |
|
327 continue; |
|
328 } |
|
329 if (len<=0) |
|
330 __LEAVE(KErrArgument); |
|
331 else if (cLen!=KDbUndefinedLength && cLen<len) |
|
332 __LEAVE(KErrArgument); |
|
333 } |
|
334 } |
|
335 } |
|
336 |
|
337 // Class RDbAccessPlan |
|
338 |
|
339 TUint RDbAccessPlan::FindMatchL(const CDbTableIndexDef* aIndex) |
|
340 // |
|
341 // Checks if index best matches the order specified |
|
342 // |
|
343 { |
|
344 CDbKey& order=iQuery->SortSpecification(); |
|
345 TInt count=order.Count(); |
|
346 const TDbColumnDef* columnDef = iTable->Def().Columns().ColumnL(order[count-1].iName); |
|
347 __ASSERT(columnDef != NULL); |
|
348 TInt columnLength = columnDef->iMaxLength; |
|
349 const CDbKey& key=aIndex->Key(); |
|
350 TUint ret=0; |
|
351 if (TextKeyL(order) && order.Comparison()!=key.Comparison()) |
|
352 return ret; |
|
353 TInt kCount=key.Count(); |
|
354 for (TInt ii=0,rev=0;;) |
|
355 { |
|
356 const TDbKeyCol& kcol=key[ii]; |
|
357 const TDbKeyCol& ocol=order[ii]; |
|
358 if (kcol.iName.CompareF(ocol.iName)!=0) |
|
359 break; |
|
360 TInt revcol=kcol.iOrder^ocol.iOrder; |
|
361 if (ii==0) |
|
362 rev=revcol; |
|
363 else if (rev!=revcol) |
|
364 break; |
|
365 if (++ii==count) // end of order key |
|
366 { |
|
367 ret|=EMatch; |
|
368 if (kcol.iLength!=columnLength) |
|
369 ret|=ETruncated; |
|
370 if (rev) |
|
371 ret|=EReverse; |
|
372 return ret; |
|
373 } |
|
374 if (ii==kCount) // end of index key |
|
375 { |
|
376 ret|=EMatch; |
|
377 if (key.IsUnique()) |
|
378 { // will provide the right order by, use it |
|
379 if (rev) |
|
380 ret|=EReverse; |
|
381 return ret; |
|
382 } |
|
383 break; |
|
384 } |
|
385 } |
|
386 return ret; |
|
387 } |
|
388 |
|
389 TBool RDbAccessPlan::TextKeyL(const CDbKey& anOrder) |
|
390 // |
|
391 // return whether any of the keys are text columns |
|
392 // |
|
393 { |
|
394 const HDbColumnSet& cols=iTable->Def().Columns(); |
|
395 TInt count=anOrder.Count(); |
|
396 for (TInt ii=0;ii<count;++ii) |
|
397 { |
|
398 const TDbColumnDef* columnDef = cols.ColumnL(anOrder[ii].iName); |
|
399 __ASSERT(columnDef != NULL); |
|
400 |
|
401 switch (columnDef->Type()) |
|
402 { |
|
403 case EDbColText8: |
|
404 case EDbColText16: |
|
405 case EDbColLongText8: |
|
406 case EDbColLongText16: |
|
407 return ETrue; |
|
408 default: |
|
409 break; |
|
410 } |
|
411 } |
|
412 return EFalse; |
|
413 } |
|
414 |
|
415 CDbTableSource* RDbAccessPlan::TableLC(CDbTableDatabase& aDatabase,const TDesC& aTable) |
|
416 { |
|
417 __ASSERT(!iSource); |
|
418 CDbTableSource* source=aDatabase.TableSourceL(aTable); |
|
419 iSource=source; |
|
420 iTable=&source->Table(); |
|
421 CleanupStack::PushL(TCleanupItem(Cleanup,this)); |
|
422 return source; |
|
423 } |
|
424 |
|
425 void RDbAccessPlan::Insert(CDbDataStage* aStage) |
|
426 { |
|
427 __ASSERT(iSource); |
|
428 aStage->SetSource(iSource); |
|
429 iSource=aStage; |
|
430 } |
|
431 |
|
432 void RDbAccessPlan::Cleanup(TAny* aPtr) |
|
433 { |
|
434 RDbAccessPlan& self=*STATIC_CAST(RDbAccessPlan*,aPtr); |
|
435 self.iPlans.Close(); |
|
436 delete self.iSource; |
|
437 } |
|
438 |
|
439 CDbRecordIter* RDbAccessPlan::IteratorL(const TPlan& aPlan) |
|
440 // |
|
441 // Returns the right iterator |
|
442 // |
|
443 { |
|
444 if (aPlan.iFlags&TPlan::EIndex) |
|
445 return iTable->IteratorL(*aPlan.iIndex); |
|
446 if (aPlan.iFlags&TPlan::EBounded) |
|
447 return BoundedIteratorL(aPlan); |
|
448 return iTable->IteratorL(); |
|
449 } |
|
450 |
|
451 CDbRecordIter* RDbAccessPlan::BoundedIteratorL(const TPlan& aPlan) |
|
452 { |
|
453 TBounds bounds(aPlan); |
|
454 CDbRecordIter* iter=iTable->IteratorL(*aPlan.iIndex,bounds.iInclusion,bounds.iLower,bounds.iUpper); |
|
455 if (aPlan.iLower) |
|
456 iQuery->RemovePredicate(aPlan.iLower); |
|
457 if (aPlan.iUpper && aPlan.iLower!=aPlan.iUpper) |
|
458 iQuery->RemovePredicate(aPlan.iUpper); |
|
459 return iter; |
|
460 } |
|
461 |
|
462 void RDbAccessPlan::RestrictionL() |
|
463 { |
|
464 CDbRestrictStage* restriction=new(ELeave) CDbRestrictStage(iComparison); |
|
465 Insert(restriction); |
|
466 CSqlSearchCondition* searchcondition=iQuery->AdoptSearchCondition(); |
|
467 restriction->SetRestriction(searchcondition); |
|
468 } |
|
469 |
|
470 void RDbAccessPlan::OrderByL(const RDbTableRow& aRowBuf) |
|
471 { |
|
472 CDbOrderByStage* ordering=new(ELeave) CDbOrderByStage(aRowBuf); |
|
473 Insert(ordering); |
|
474 ordering->ConstructL(iQuery->SortSpecification()); |
|
475 } |
|
476 |
|
477 void RDbAccessPlan::ProjectionL() |
|
478 { |
|
479 CDbProjectStage* projection=new(ELeave) CDbProjectStage; |
|
480 Insert(projection); |
|
481 projection->ConstructL(iQuery->ColumnList(),iTable->Def().Columns()); |
|
482 } |
|
483 |
|
484 void RDbAccessPlan::WindowL(const TPlan& aPlan,const TDbWindow& aWindow) |
|
485 { |
|
486 if (aPlan.iFlags&TPlan::EWindow) |
|
487 Insert(new(ELeave) CDbWindowStage(KDbUnlimitedWindow)); |
|
488 else if (aWindow.Size()!=aWindow.ENone && aWindow.Size()!=aWindow.EUnlimited) |
|
489 Insert(new(ELeave) CDbWindowStage(aWindow)); |
|
490 } |
|
491 |
|
492 TBool RDbAccessPlan::IsIndexIteratorL(TPlan& aPlan,const CDbTableIndexDef* aIndex) |
|
493 // |
|
494 // If an index iterator can be used, sets aPlan, else returns EFalse |
|
495 // |
|
496 { |
|
497 if (!iQuery->HasSortSpecification()) |
|
498 return EFalse; |
|
499 TUint ret=FindMatchL(aIndex); |
|
500 if ((ret&EMatch)==0) |
|
501 return EFalse; |
|
502 // can use index iterator |
|
503 aPlan.iFlags&=~TPlan::EOrder; |
|
504 if (ret&EReverse) |
|
505 aPlan.iFlags|=TPlan::EReverse; |
|
506 aPlan.iFlags|=TPlan::EIndex; |
|
507 aPlan.iIndex=aIndex; |
|
508 return ETrue; |
|
509 } |
|
510 |
|
511 TBool RDbAccessPlan::IsBoundedIteratorL(TPlan& aPlan,const CDbTableIndexDef* aIndex) |
|
512 // |
|
513 // If a bounded iterator can be used, sets aPlan, else returns EFalse |
|
514 // |
|
515 { |
|
516 if (!iQuery->HasSearchCondition()) |
|
517 return EFalse; |
|
518 TDbColNo keyColNo=iTable->Def().Columns().ColNoL(aIndex->Key()[0].iName); |
|
519 CDbCompPredicateList* list=CDbCompPredicateList::NewLC(*iQuery,iComparison,iTable->Def()); |
|
520 CSqlCompPredicate* cp=list->CompPredicate(keyColNo,CDbCompPredicateList::EEqual); |
|
521 if (cp==0 && (cp=list->CompPredicate(keyColNo))==0) |
|
522 { |
|
523 CleanupStack::PopAndDestroy(); // list |
|
524 return EFalse; |
|
525 } |
|
526 // boundaries |
|
527 TUint type=list->Type(cp->NodeType()); |
|
528 aPlan.iLower=type&(CDbCompPredicateList::ELess|CDbCompPredicateList::ELessEqual)?0:cp; |
|
529 aPlan.iUpper=type&(CDbCompPredicateList::EGreater|CDbCompPredicateList::EGreaterEqual)?0:cp; |
|
530 // find other boundary, if present |
|
531 if (list->Count()!=0 && cp->NodeType()!=CSqlSearchCondition::EEqual) |
|
532 { |
|
533 TUint nextType=type&(CDbCompPredicateList::ELess|CDbCompPredicateList::ELessEqual) ? |
|
534 CDbCompPredicateList::EGreater|CDbCompPredicateList::EGreaterEqual : |
|
535 CDbCompPredicateList::ELess|CDbCompPredicateList::ELessEqual; |
|
536 CSqlCompPredicate* cp2=list->CompPredicate(keyColNo,nextType); |
|
537 if (cp2) |
|
538 { |
|
539 if (nextType&(CDbCompPredicateList::ELess|CDbCompPredicateList::ELessEqual)) |
|
540 aPlan.iUpper=cp2; |
|
541 else |
|
542 aPlan.iLower=cp2; |
|
543 } |
|
544 } |
|
545 // check which order the index is in and reverse if descending |
|
546 const TDbKeyCol& key=aIndex->Key()[0]; |
|
547 if ((key.iOrder==TDbKeyCol::EDesc && !aPlan.iUpper) || (key.iOrder==TDbKeyCol::EAsc && !aPlan.iLower)) |
|
548 aPlan.iFlags|=TPlan::EReverse; // optimise the bounding for forwards iteration |
|
549 if (!list->IsRestriction() && list->Count()==0) |
|
550 aPlan.iFlags&=~TPlan::ERestrict; |
|
551 CleanupStack::PopAndDestroy(); // list |
|
552 aPlan.iFlags|=TPlan::EBounded; |
|
553 aPlan.iIndex=aIndex; |
|
554 return ETrue; |
|
555 } |
|
556 |
|
557 void RDbAccessPlan::EvaluatePlansL() |
|
558 // |
|
559 // try to find a bounded or index iterator |
|
560 // |
|
561 { |
|
562 TPlan plan; |
|
563 // initialise flags |
|
564 if (iQuery->HasSearchCondition()) |
|
565 plan.iFlags|=TPlan::ERestrict; |
|
566 if (iQuery->HasSortSpecification()) |
|
567 plan.iFlags|=TPlan::EOrder; |
|
568 // find the right type of iterator |
|
569 TSglQueIterC<CDbTableIndexDef> indexes(iTable->Def().Indexes().AsQue()); |
|
570 for (const CDbTableIndexDef* index;(index=indexes++)!=0;) |
|
571 { // only on first column |
|
572 TPlan newPlan=plan; |
|
573 TBool foundIter=IsBoundedIteratorL(newPlan,index); |
|
574 if (!foundIter) |
|
575 foundIter=IsIndexIteratorL(newPlan,index); |
|
576 else |
|
577 EvaluateReorderStage(newPlan,index); |
|
578 if (foundIter) |
|
579 { |
|
580 EvaluateWindowStage(newPlan); |
|
581 __LEAVE_IF_ERROR(iPlans.Append(newPlan)); |
|
582 } |
|
583 } |
|
584 } |
|
585 |
|
586 void RDbAccessPlan::ChoosePlanL(TPlan& aPlan) |
|
587 { |
|
588 ReducePlans(); |
|
589 if (iPlans.Count()==0) |
|
590 { |
|
591 CreateTableIteratorPlan(aPlan); |
|
592 return; |
|
593 } |
|
594 TPlan::TType type=iPlans[0].Type(); |
|
595 if (!iQuery->HasSearchCondition()) |
|
596 { |
|
597 __ASSERT(type==TPlan::EPlanEF); |
|
598 GetSmallestKeySize(aPlan,TPlan::EPlanEF); |
|
599 } |
|
600 else if (!iQuery->HasSortSpecification()) |
|
601 { |
|
602 if (type==TPlan::EPlanIJ) |
|
603 { |
|
604 GetSmallestKeySize(aPlan,TPlan::EPlanIJ); |
|
605 TInt r=IndexSpanL(aPlan); |
|
606 if (r!=CDbTable::EUnavailableSpan && !iWindow && r>60) |
|
607 CreateTableIteratorPlan(aPlan); |
|
608 } |
|
609 else if (type==TPlan::EPlanOP) |
|
610 { |
|
611 TInt r=GetTightestRestrictionL(aPlan,TPlan::EPlanOP); |
|
612 if (r==CDbTable::EUnavailableSpan) // no index stats available |
|
613 aPlan=iPlans[0]; // use first O/P as a guess |
|
614 else if ((!iWindow && r>55) || (iWindow && r>60)) |
|
615 CreateTableIteratorPlan(aPlan); |
|
616 } |
|
617 else |
|
618 __ASSERT(0); |
|
619 } |
|
620 else if (type==TPlan::EPlanMN) |
|
621 { |
|
622 GetSmallestKeySize(aPlan,TPlan::EPlanMN); |
|
623 if (iAccess==RDbRowSet::EUpdatable || iWindow) |
|
624 aPlan.iFlags|=TPlan::EWindow; |
|
625 } |
|
626 else if (type==TPlan::EPlanKL) |
|
627 { |
|
628 GetSmallestKeySize(aPlan,TPlan::EPlanKL); |
|
629 TInt r=IndexSpanL(aPlan); |
|
630 if (r!=CDbTable::EUnavailableSpan && r>60) |
|
631 { // don't use K plan |
|
632 if (r<75 || GetSmallestKeySize(aPlan,TPlan::EPlanGH)==KErrNotFound) |
|
633 CreateTableIteratorPlan(aPlan); |
|
634 } |
|
635 } |
|
636 else if (type==TPlan::EPlanQR) |
|
637 { |
|
638 TInt r=GetTightestRestrictionL(aPlan,TPlan::EPlanQR); |
|
639 if (r==CDbTable::EUnavailableSpan) // no index stats available |
|
640 aPlan=iPlans[0]; // use first Q/R as a guess |
|
641 else if (r>60) |
|
642 CreateTableIteratorPlan(aPlan); |
|
643 } |
|
644 else |
|
645 { |
|
646 __ASSERT(type==TPlan::EPlanGH); |
|
647 // don't use this plan without further data, resort to default |
|
648 CreateTableIteratorPlan(aPlan); |
|
649 } |
|
650 } |
|
651 |
|
652 void RDbAccessPlan::EvaluateWindowStage(TPlan& aPlan) |
|
653 { |
|
654 if (!iWindow) |
|
655 return; |
|
656 TUint f=aPlan.iFlags|TPlan::EWindow; |
|
657 if (f&TPlan::EReorder) |
|
658 f&=~TPlan::EWindow; |
|
659 if (f&TPlan::ERestrict) |
|
660 f|=TPlan::EWindow; |
|
661 if (f&TPlan::EOrder) // order-by stage includes window |
|
662 f&=~TPlan::EWindow; |
|
663 aPlan.iFlags=f; |
|
664 } |
|
665 |
|
666 TInt RDbAccessPlan::GetTightestRestrictionL(TPlan& aPlan,TPlan::TType aType) |
|
667 // |
|
668 // aPlan is set to the smallest restricted plan with aType |
|
669 // |
|
670 { |
|
671 TInt span=KMaxTInt; |
|
672 TPlan plan; |
|
673 for (TInt ii=iPlans.Count();ii--;) |
|
674 { |
|
675 if (iPlans[ii].Type()!=aType) |
|
676 continue; |
|
677 TInt t=IndexSpanL(iPlans[ii]); |
|
678 if (t==CDbTable::EUnavailableSpan) |
|
679 continue; |
|
680 __ASSERT(t == span ? (iPlans[ii].iIndex != NULL && plan.iIndex != NULL) : ETrue); |
|
681 //coverity[uninit_use_in_call] |
|
682 if (t<span || (t==span && iPlans[ii].iIndex->Key().Count()<plan.iIndex->Key().Count())) |
|
683 { |
|
684 span=t; |
|
685 plan=iPlans[ii]; |
|
686 } |
|
687 } |
|
688 aPlan=plan; |
|
689 return span!=KMaxTInt?span:CDbTable::EUnavailableSpan; |
|
690 } |
|
691 |
|
692 TInt RDbAccessPlan::GetSmallestKeySize(TPlan& aPlan,TPlan::TType aType) |
|
693 // |
|
694 // aPlan is set to the plan with smallest index with aType |
|
695 // |
|
696 { |
|
697 TInt cols=KMaxTInt; |
|
698 TPlan plan; |
|
699 for (TInt ii=iPlans.Count();ii--;) |
|
700 { |
|
701 if (iPlans[ii].Type()!=aType) |
|
702 continue; |
|
703 __ASSERT(iPlans[ii].iIndex); |
|
704 TInt count=iPlans[ii].iIndex->Key().Count(); |
|
705 if (count<cols) |
|
706 { |
|
707 cols=count; |
|
708 plan=iPlans[ii]; |
|
709 } |
|
710 } |
|
711 aPlan=plan; |
|
712 return cols!=KMaxTInt?cols:KErrNotFound; |
|
713 } |
|
714 |
|
715 TInt RDbAccessPlan::IndexSpanL(const TPlan& aPlan) |
|
716 { |
|
717 __ASSERT(aPlan.iIndex); |
|
718 TBounds bounds(aPlan); |
|
719 return iTable->IndexSpanL(*aPlan.iIndex,bounds.iInclusion,bounds.iLower,bounds.iUpper); |
|
720 } |
|
721 |
|
722 void RDbAccessPlan::ReducePlans() |
|
723 { |
|
724 for (TInt ii=iPlans.Count();--ii>=0;) |
|
725 { |
|
726 switch (iPlans[ii].Type()) |
|
727 { |
|
728 default: |
|
729 continue; |
|
730 case TPlan::EPlanGH: |
|
731 if (iWindow) |
|
732 iPlans.Remove(ii); // remove Gw/Hw |
|
733 break; |
|
734 case TPlan::EPlanST: |
|
735 iPlans[ii].iFlags|=(TPlan::EReorder|TPlan::EOrder); // convert S/T to Q/R |
|
736 EvaluateWindowStage(iPlans[ii]); |
|
737 break; |
|
738 }; |
|
739 } |
|
740 // explicit conversion required as GCC can't find the TLinearOrder instantiation |
|
741 iPlans.Sort(TLinearOrder<TPlan>(TPlan::OrderByPlan)); |
|
742 } |
|
743 |
|
744 void RDbAccessPlan::CreateTableIteratorPlan(TPlan& aPlan) |
|
745 { |
|
746 aPlan.iFlags&=~(TPlan::EIndex|TPlan::EBounded); |
|
747 if (iQuery->HasSearchCondition()) |
|
748 aPlan.iFlags=TPlan::ERestrict; |
|
749 if (iQuery->HasSortSpecification()) |
|
750 aPlan.iFlags|=TPlan::EOrder; |
|
751 EvaluateWindowStage(aPlan); |
|
752 } |
|
753 |
|
754 void RDbAccessPlan::EvaluateReorderStage(TPlan& aPlan,const CDbTableIndexDef* aIndex) |
|
755 // |
|
756 // for a bounded iter with an order by - can the index be used? |
|
757 // |
|
758 { |
|
759 aPlan.iFlags|=TPlan::EReorder; |
|
760 if (!iQuery->HasSortSpecification()) |
|
761 return; |
|
762 TUint ret=0; |
|
763 TRAPD(errCode, ret=FindMatchL(aIndex)); |
|
764 if (errCode==KErrNone && ret&EMatch) |
|
765 {// do we really need a reorder stage? |
|
766 aPlan.iFlags&=~TPlan::EOrder; // don't need to order it |
|
767 aPlan.iFlags&=~TPlan::EReorder; // don't need a reorder stage |
|
768 if (ret&EReverse) |
|
769 aPlan.iFlags|=TPlan::EReverse; |
|
770 else |
|
771 aPlan.iFlags&=~TPlan::EReverse; |
|
772 } |
|
773 } |
|
774 |
|
775 void RDbAccessPlan::PrepareQueryL(CDbTableSource* aSource) |
|
776 { |
|
777 if (iQuery->HasSearchCondition()) |
|
778 { |
|
779 CSqlSearchCondition& sc=iQuery->SearchCondition(); |
|
780 sc.BindL(aSource->Row()); |
|
781 } |
|
782 if (iQuery->HasSortSpecification()) |
|
783 { |
|
784 CDbKey& order=iQuery->SortSpecification(); |
|
785 order.SetComparison(iComparison); |
|
786 Validate::KeyL(order,iTable->Def().Columns()); |
|
787 } |
|
788 } |
|
789 |
|
790 |
|
791 void RDbAccessPlan::BuildLC(CDbTableDatabase& aDatabase,RDbRowSet::TAccess aAccess,const TDbWindow& aWindow) |
|
792 // |
|
793 // Prepare the data pipeline |
|
794 // |
|
795 { |
|
796 __ASSERT(iQuery); |
|
797 CDbTableSource* source=TableLC(aDatabase,iQuery->Table()); |
|
798 // |
|
799 if (aAccess!=RDbRowSet::EInsertOnly) |
|
800 { // insert only views do not use Iterators, Restrictions or Windows |
|
801 iWindow=aWindow.Size()==aWindow.EUnlimited; |
|
802 iAccess=aAccess; |
|
803 PrepareQueryL(source); |
|
804 EvaluatePlansL(); |
|
805 TPlan plan; |
|
806 ChoosePlanL(plan); |
|
807 source->SetIterator(IteratorL(plan)); |
|
808 if (plan.iFlags&TPlan::EReorder) |
|
809 Insert(new(ELeave) CDbReorderWindowStage); |
|
810 if (plan.iFlags&TPlan::EReverse) |
|
811 source->ReverseIteratorL(); |
|
812 if (plan.iFlags&TPlan::ERestrict) |
|
813 RestrictionL(); |
|
814 if (plan.iFlags&TPlan::EOrder) |
|
815 OrderByL(source->Row()); |
|
816 WindowL(plan,aWindow); |
|
817 iPlans.Reset(); |
|
818 } |
|
819 if (iQuery->HasColumnList()) |
|
820 ProjectionL(); |
|
821 } |
|
822 |
|
823 void RDbAccessPlan::BuildLC(CDbTableDatabase& aDatabase,const TDesC& aTable,RDbRowSet::TAccess aAccess) |
|
824 { |
|
825 CDbTableSource* source=TableLC(aDatabase,aTable); |
|
826 if (aAccess!=RDbRowSet::EInsertOnly) |
|
827 source->SetIterator(iTable->IteratorL()); |
|
828 } |