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