sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "UT_STD.H" sl@0: #include "D32COMP.H" sl@0: #include "U32STD_DBMS.H" sl@0: sl@0: // Class RDbAccessPlan::TPlan sl@0: sl@0: TInt RDbAccessPlan::TPlan::OrderByPlan(const TPlan& aLeft,const TPlan& aRight) sl@0: { sl@0: TUint lpos=aLeft.Type(); sl@0: TUint rpos=aRight.Type(); sl@0: __ASSERT(lpos!=0 && rpos!=0 ); // should be no table iterators sl@0: return lpos-rpos; sl@0: } sl@0: sl@0: RDbAccessPlan::TPlan::TType RDbAccessPlan::TPlan::Type() const sl@0: // sl@0: // 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 sl@0: // This determines order of plans sl@0: // sl@0: { sl@0: const TUint KPosition[]={EPlanA,EPlanC,EPlanB,EPlanD,0,0,0,0,EPlanEF,0,EPlanGH,0,0,0,0,0,EPlanMN, sl@0: 0,EPlanST,0,EPlanIJ,EPlanKL,EPlanOP,EPlanQR}; sl@0: return TType(KPosition[iFlags&EMask]); sl@0: } sl@0: sl@0: // Class RDbAccessPlan::TBounds sl@0: sl@0: RDbAccessPlan::TBounds::TBounds(const TPlan& aPlan) sl@0: : iLowerPred(aPlan.iLower),iUpperPred(aPlan.iUpper),iLower(0),iUpper(0),iInclusion(0) sl@0: { sl@0: SetLowerBounds(); sl@0: SetUpperBounds(); sl@0: if (aPlan.iIndex->Key()[0].iOrder==TDbKeyCol::EDesc) sl@0: { sl@0: TDbLookupKey* t=iLower; sl@0: iLower=iUpper; sl@0: iUpper=t; sl@0: iInclusion=(iInclusion>>1)|(iInclusion<<1); sl@0: } sl@0: } sl@0: sl@0: void RDbAccessPlan::TBounds::GetLookupKey(const CSqlCompPredicate& aCompPredicate,TDbLookupKey& aLookup) sl@0: { sl@0: const RSqlLiteral& value=aCompPredicate.Value(); sl@0: switch (aCompPredicate.ColType()) sl@0: { sl@0: default: sl@0: __ASSERT(0); sl@0: case EDbColBit: sl@0: case EDbColInt8: sl@0: case EDbColUint8: sl@0: case EDbColInt16: sl@0: case EDbColUint16: sl@0: case EDbColInt32: sl@0: case EDbColUint32: sl@0: case EDbColInt64: sl@0: aLookup.Add(value.Int64()); sl@0: break; sl@0: case EDbColReal32: sl@0: case EDbColReal64: sl@0: aLookup.Add(value.Real64()); sl@0: break; sl@0: case EDbColDateTime: sl@0: aLookup.Add(value.Time()); sl@0: break; sl@0: case EDbColText8: sl@0: case EDbColLongText8: sl@0: aLookup.Add(value.Text8()); sl@0: break; sl@0: case EDbColText16: sl@0: case EDbColLongText16: sl@0: aLookup.Add(value.Text16()); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: void RDbAccessPlan::TBounds::SetLowerBounds() sl@0: { sl@0: if (!iLowerPred) // iLower already set to 0 sl@0: return; sl@0: GetLookupKey(*iLowerPred,iLowerKey); sl@0: switch (iLowerPred->NodeType()) sl@0: { sl@0: default: sl@0: __ASSERT(0); sl@0: case CSqlSearchCondition::ELessEqual: sl@0: case CSqlSearchCondition::ELess: sl@0: iLower=0; sl@0: break; sl@0: case CSqlSearchCondition::EEqual: sl@0: case CSqlSearchCondition::EGreaterEqual: sl@0: iInclusion|=CDbRecordIndex::EIncludeLower; sl@0: case CSqlSearchCondition::EGreater: sl@0: iLower=&iLowerKey; sl@0: break; sl@0: } sl@0: } sl@0: sl@0: void RDbAccessPlan::TBounds::SetUpperBounds() sl@0: { sl@0: if (!iUpperPred) sl@0: return; sl@0: GetLookupKey(*iUpperPred,iUpperKey); sl@0: switch (iUpperPred->NodeType()) sl@0: { sl@0: default: sl@0: __ASSERT(0); sl@0: case CSqlSearchCondition::EGreaterEqual: sl@0: case CSqlSearchCondition::EGreater: sl@0: iUpper=0; sl@0: break; sl@0: case CSqlSearchCondition::EEqual: sl@0: case CSqlSearchCondition::ELessEqual: sl@0: iInclusion|=CDbRecordIndex::EIncludeUpper; sl@0: case CSqlSearchCondition::ELess: sl@0: iUpper=&iUpperKey; sl@0: break; sl@0: } sl@0: } sl@0: sl@0: // Class RDbAccessPlan::CDbCompPredicateList sl@0: sl@0: RDbAccessPlan::CDbCompPredicateList* RDbAccessPlan::CDbCompPredicateList::NewLC(CSqlQuery& aQuery,TDbTextComparison aComparison,const CDbTableDef& aTableDef) sl@0: { sl@0: CDbCompPredicateList* self=new(ELeave) CDbCompPredicateList(aTableDef,aComparison); sl@0: CleanupStack::PushL(self); sl@0: CSqlSearchCondition& sc=aQuery.SearchCondition(); sl@0: self->ConstructL(sc); sl@0: return self; sl@0: } sl@0: sl@0: void RDbAccessPlan::CDbCompPredicateList::ConstructL(CSqlSearchCondition& aSearchCondition) sl@0: // sl@0: // fill the list with valid comp pred's sl@0: // sl@0: { sl@0: TUint type=Type(aSearchCondition.NodeType()); sl@0: if (type&ECompPred) sl@0: { sl@0: CSqlCompPredicate* cp=aSearchCondition.CompPredicate(); sl@0: const TDesC& colName=cp->ColumnName(); sl@0: if (IsIndexed(colName)) sl@0: AppendL(cp); sl@0: else sl@0: iRestriction=ETrue; sl@0: } sl@0: else if (type&EAnd) sl@0: { sl@0: CSqlMultiNode* multiNode=aSearchCondition.MultiNode(); sl@0: for (TInt ii=multiNode->Count();ii--;) sl@0: { sl@0: CSqlSearchCondition* node=multiNode->SubNode(ii); sl@0: ConstructL(*node); sl@0: } sl@0: } sl@0: else sl@0: iRestriction=ETrue; sl@0: } sl@0: sl@0: TUint RDbAccessPlan::CDbCompPredicateList::Type(CSqlSearchCondition::TType aType) const sl@0: // sl@0: // converts CSqlSearchCondition::TType into flag sl@0: // sl@0: { sl@0: switch (aType) sl@0: { sl@0: case CSqlSearchCondition::EAnd: sl@0: return EAnd; sl@0: case CSqlSearchCondition::ELess: sl@0: return ELess; sl@0: case CSqlSearchCondition::ELessEqual: sl@0: return ELessEqual; sl@0: case CSqlSearchCondition::EEqual: sl@0: return EEqual; sl@0: case CSqlSearchCondition::EGreaterEqual: sl@0: return EGreaterEqual; sl@0: case CSqlSearchCondition::EGreater: sl@0: return EGreater; sl@0: default: sl@0: return ENone; sl@0: } sl@0: } sl@0: sl@0: TBool RDbAccessPlan::CDbCompPredicateList::IsIndexed(const TDesC& aColumnName) sl@0: // sl@0: // Checks if aColumnName is indexed. If its a text column the comparison method should be the same sl@0: // sl@0: { sl@0: const CDbTableIndexDef* key=iTableDef.Key(aColumnName); sl@0: if (!key) sl@0: return EFalse; sl@0: const TDbColumnDef* colDef=NULL; sl@0: TRAPD(errCode, colDef=iTableDef.Columns().ColumnL(aColumnName)); sl@0: if(errCode != KErrNone) sl@0: return EFalse; sl@0: if (colDef->Type()>EDbColDateTime && key->Key().Comparison()!=iComparison) sl@0: return EFalse; sl@0: return ETrue; sl@0: } sl@0: sl@0: CSqlCompPredicate* RDbAccessPlan::CDbCompPredicateList::CompPredicate(TDbColNo aColNo,TUint aType) sl@0: // sl@0: // Returns first CompPredicate found in the list with required type & col no, and removes from list sl@0: // sl@0: { sl@0: for (TInt ii=Count();ii--;) sl@0: { sl@0: CSqlCompPredicate* cp=At(ii); sl@0: TUint type=Type(cp->NodeType()); sl@0: TDbColNo colNo=cp->ColNo(); sl@0: if (!type&aType || aColNo!=colNo) sl@0: continue; sl@0: Delete(ii); sl@0: return cp; sl@0: } sl@0: return 0; sl@0: } sl@0: sl@0: // class Validate sl@0: sl@0: void Validate::NameL(const TDesC& aName) sl@0: { sl@0: if (aName.Length()<=KDbMaxName) sl@0: { sl@0: TLex lex(aName); sl@0: if (!lex.Eos() && lex.Get().IsAlpha()) sl@0: { sl@0: TChar c; sl@0: do sl@0: { sl@0: if (lex.Eos()) sl@0: return; sl@0: c=lex.Get(); sl@0: } while (c.IsAlphaDigit()||c=='_'); sl@0: } sl@0: } sl@0: __LEAVE(KErrBadName); sl@0: } sl@0: sl@0: void Validate::UniqueNameL(TDesC const** aNames,TInt aCount,const TDesC& aName) sl@0: // sl@0: // Ensure that aName is not a duplicate of any of aNames, and add sl@0: // the new name to the collection. Binary search is used for speed sl@0: // sl@0: { sl@0: TInt left=0; sl@0: TInt right=aCount; sl@0: while (left>1; sl@0: TInt c=aNames[mid]->CompareF(aName); sl@0: if (c<0) sl@0: left=mid+1; sl@0: else if (c>0) sl@0: right=mid; sl@0: else sl@0: __LEAVE(KErrArgument); sl@0: } sl@0: Mem::Move(aNames+left+1,aNames+left,(aCount-left)*sizeof(TDesC const*)); sl@0: aNames[left]=&aName; sl@0: } sl@0: sl@0: void Validate::ColSetL(const CDbColSet& aColSet) sl@0: { sl@0: TDbColSetIter iter(aColSet); sl@0: if (!iter) sl@0: __LEAVE(KErrArgument); sl@0: TDesC const** names=(TDesC const**)User::AllocLC(aColSet.Count()*sizeof(TDesC const*)); sl@0: do sl@0: { sl@0: const TDbCol& col=*iter; sl@0: NameL(col.iName); sl@0: UniqueNameL(names,iter.Col()-1,col.iName); sl@0: TInt type=TInt(col.iType); sl@0: if (typeTInt(EDbColLongBinary)) sl@0: __LEAVE(KErrNotSupported); sl@0: else if (col.iMaxLength<1&&col.iMaxLength!=KDbUndefinedLength) sl@0: __LEAVE(KErrArgument); sl@0: else if (col.iAttributes&~(TDbCol::ENotNull|TDbCol::EAutoIncrement)) sl@0: __LEAVE(KErrNotSupported); // unknown attributes sl@0: else if (type>EDbColUint32 && col.iAttributes&TDbCol::EAutoIncrement) sl@0: __LEAVE(KErrArgument); // auto increment on non-integral type sl@0: } while (++iter); sl@0: CleanupStack::PopAndDestroy(); sl@0: } sl@0: sl@0: void Validate::KeyL(const CDbKey& aKey,const HDbColumnSet& aColumns) sl@0: // sl@0: // Check that the key is valid for the table sl@0: // sl@0: { sl@0: TInt max=aKey.Count()-1; sl@0: if (max<0) sl@0: __LEAVE(KErrArgument); sl@0: for (TInt ii=0;ii<=max;++ii) sl@0: { sl@0: const TDbKeyCol& kCol=aKey[ii]; sl@0: HDbColumnSet::TIteratorC col=aColumns.ColumnL(kCol.iName); sl@0: if (col==NULL) sl@0: __LEAVE(KErrNotFound); sl@0: TInt len=kCol.iLength; sl@0: if (len!=KDbUndefinedLength) sl@0: { sl@0: if (col->iType<=EDbColDateTime) sl@0: __LEAVE(KErrArgument); sl@0: TInt cLen=col->iMaxLength; sl@0: if (iiSortSpecification(); sl@0: TInt count=order.Count(); sl@0: TInt columnLength=iTable->Def().Columns().ColumnL(order[count-1].iName)->iMaxLength; sl@0: const CDbKey& key=aIndex->Key(); sl@0: TUint ret=0; sl@0: if (TextKeyL(order) && order.Comparison()!=key.Comparison()) sl@0: return ret; sl@0: TInt kCount=key.Count(); sl@0: for (TInt ii=0,rev=0;;) sl@0: { sl@0: const TDbKeyCol& kcol=key[ii]; sl@0: const TDbKeyCol& ocol=order[ii]; sl@0: if (kcol.iName.CompareF(ocol.iName)!=0) sl@0: break; sl@0: TInt revcol=kcol.iOrder^ocol.iOrder; sl@0: if (ii==0) sl@0: rev=revcol; sl@0: else if (rev!=revcol) sl@0: break; sl@0: if (++ii==count) // end of order key sl@0: { sl@0: ret|=EMatch; sl@0: if (kcol.iLength!=columnLength) sl@0: ret|=ETruncated; sl@0: if (rev) sl@0: ret|=EReverse; sl@0: return ret; sl@0: } sl@0: if (ii==kCount) // end of index key sl@0: { sl@0: ret|=EMatch; sl@0: if (key.IsUnique()) sl@0: { // will provide the right order by, use it sl@0: if (rev) sl@0: ret|=EReverse; sl@0: return ret; sl@0: } sl@0: break; sl@0: } sl@0: } sl@0: return ret; sl@0: } sl@0: sl@0: TBool RDbAccessPlan::TextKeyL(const CDbKey& anOrder) sl@0: // sl@0: // return whether any of the keys are text columns sl@0: // sl@0: { sl@0: const HDbColumnSet& cols=iTable->Def().Columns(); sl@0: TInt count=anOrder.Count(); sl@0: for (TInt ii=0;iiType()) sl@0: { sl@0: case EDbColText8: sl@0: case EDbColText16: sl@0: case EDbColLongText8: sl@0: case EDbColLongText16: sl@0: return ETrue; sl@0: default: sl@0: break; sl@0: } sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: CDbTableSource* RDbAccessPlan::TableLC(CDbTableDatabase& aDatabase,const TDesC& aTable) sl@0: { sl@0: __ASSERT(!iSource); sl@0: CDbTableSource* source=aDatabase.TableSourceL(aTable); sl@0: iSource=source; sl@0: iTable=&source->Table(); sl@0: CleanupStack::PushL(TCleanupItem(Cleanup,this)); sl@0: return source; sl@0: } sl@0: sl@0: void RDbAccessPlan::Insert(CDbDataStage* aStage) sl@0: { sl@0: __ASSERT(iSource); sl@0: aStage->SetSource(iSource); sl@0: iSource=aStage; sl@0: } sl@0: sl@0: void RDbAccessPlan::Cleanup(TAny* aPtr) sl@0: { sl@0: RDbAccessPlan& self=*STATIC_CAST(RDbAccessPlan*,aPtr); sl@0: self.iPlans.Close(); sl@0: delete self.iSource; sl@0: } sl@0: sl@0: CDbRecordIter* RDbAccessPlan::IteratorL(const TPlan& aPlan) sl@0: // sl@0: // Returns the right iterator sl@0: // sl@0: { sl@0: if (aPlan.iFlags&TPlan::EIndex) sl@0: return iTable->IteratorL(*aPlan.iIndex); sl@0: if (aPlan.iFlags&TPlan::EBounded) sl@0: return BoundedIteratorL(aPlan); sl@0: return iTable->IteratorL(); sl@0: } sl@0: sl@0: CDbRecordIter* RDbAccessPlan::BoundedIteratorL(const TPlan& aPlan) sl@0: { sl@0: TBounds bounds(aPlan); sl@0: CDbRecordIter* iter=iTable->IteratorL(*aPlan.iIndex,bounds.iInclusion,bounds.iLower,bounds.iUpper); sl@0: if (aPlan.iLower) sl@0: iQuery->RemovePredicate(aPlan.iLower); sl@0: if (aPlan.iUpper && aPlan.iLower!=aPlan.iUpper) sl@0: iQuery->RemovePredicate(aPlan.iUpper); sl@0: return iter; sl@0: } sl@0: sl@0: void RDbAccessPlan::RestrictionL() sl@0: { sl@0: CDbRestrictStage* restriction=new(ELeave) CDbRestrictStage(iComparison); sl@0: Insert(restriction); sl@0: CSqlSearchCondition* searchcondition=iQuery->AdoptSearchCondition(); sl@0: restriction->SetRestriction(searchcondition); sl@0: } sl@0: sl@0: void RDbAccessPlan::OrderByL(const RDbTableRow& aRowBuf) sl@0: { sl@0: CDbOrderByStage* ordering=new(ELeave) CDbOrderByStage(aRowBuf); sl@0: Insert(ordering); sl@0: ordering->ConstructL(iQuery->SortSpecification()); sl@0: } sl@0: sl@0: void RDbAccessPlan::ProjectionL() sl@0: { sl@0: CDbProjectStage* projection=new(ELeave) CDbProjectStage; sl@0: Insert(projection); sl@0: projection->ConstructL(iQuery->ColumnList(),iTable->Def().Columns()); sl@0: } sl@0: sl@0: void RDbAccessPlan::WindowL(const TPlan& aPlan,const TDbWindow& aWindow) sl@0: { sl@0: if (aPlan.iFlags&TPlan::EWindow) sl@0: Insert(new(ELeave) CDbWindowStage(KDbUnlimitedWindow)); sl@0: else if (aWindow.Size()!=aWindow.ENone && aWindow.Size()!=aWindow.EUnlimited) sl@0: Insert(new(ELeave) CDbWindowStage(aWindow)); sl@0: } sl@0: sl@0: TBool RDbAccessPlan::IsIndexIteratorL(TPlan& aPlan,const CDbTableIndexDef* aIndex) sl@0: // sl@0: // If an index iterator can be used, sets aPlan, else returns EFalse sl@0: // sl@0: { sl@0: if (!iQuery->HasSortSpecification()) sl@0: return EFalse; sl@0: TUint ret=FindMatchL(aIndex); sl@0: if ((ret&EMatch)==0) sl@0: return EFalse; sl@0: // can use index iterator sl@0: aPlan.iFlags&=~TPlan::EOrder; sl@0: if (ret&EReverse) sl@0: aPlan.iFlags|=TPlan::EReverse; sl@0: aPlan.iFlags|=TPlan::EIndex; sl@0: aPlan.iIndex=aIndex; sl@0: return ETrue; sl@0: } sl@0: sl@0: TBool RDbAccessPlan::IsBoundedIteratorL(TPlan& aPlan,const CDbTableIndexDef* aIndex) sl@0: // sl@0: // If a bounded iterator can be used, sets aPlan, else returns EFalse sl@0: // sl@0: { sl@0: if (!iQuery->HasSearchCondition()) sl@0: return EFalse; sl@0: TDbColNo keyColNo=iTable->Def().Columns().ColNoL(aIndex->Key()[0].iName); sl@0: CDbCompPredicateList* list=CDbCompPredicateList::NewLC(*iQuery,iComparison,iTable->Def()); sl@0: CSqlCompPredicate* cp=list->CompPredicate(keyColNo,CDbCompPredicateList::EEqual); sl@0: if (cp==0 && (cp=list->CompPredicate(keyColNo))==0) sl@0: { sl@0: CleanupStack::PopAndDestroy(); // list sl@0: return EFalse; sl@0: } sl@0: // boundaries sl@0: TUint type=list->Type(cp->NodeType()); sl@0: aPlan.iLower=type&(CDbCompPredicateList::ELess|CDbCompPredicateList::ELessEqual)?0:cp; sl@0: aPlan.iUpper=type&(CDbCompPredicateList::EGreater|CDbCompPredicateList::EGreaterEqual)?0:cp; sl@0: // find other boundary, if present sl@0: if (list->Count()!=0 && cp->NodeType()!=CSqlSearchCondition::EEqual) sl@0: { sl@0: TUint nextType=type&(CDbCompPredicateList::ELess|CDbCompPredicateList::ELessEqual) ? sl@0: CDbCompPredicateList::EGreater|CDbCompPredicateList::EGreaterEqual : sl@0: CDbCompPredicateList::ELess|CDbCompPredicateList::ELessEqual; sl@0: CSqlCompPredicate* cp2=list->CompPredicate(keyColNo,nextType); sl@0: if (cp2) sl@0: { sl@0: if (nextType&(CDbCompPredicateList::ELess|CDbCompPredicateList::ELessEqual)) sl@0: aPlan.iUpper=cp2; sl@0: else sl@0: aPlan.iLower=cp2; sl@0: } sl@0: } sl@0: // check which order the index is in and reverse if descending sl@0: const TDbKeyCol& key=aIndex->Key()[0]; sl@0: if ((key.iOrder==TDbKeyCol::EDesc && !aPlan.iUpper) || (key.iOrder==TDbKeyCol::EAsc && !aPlan.iLower)) sl@0: aPlan.iFlags|=TPlan::EReverse; // optimise the bounding for forwards iteration sl@0: if (!list->IsRestriction() && list->Count()==0) sl@0: aPlan.iFlags&=~TPlan::ERestrict; sl@0: CleanupStack::PopAndDestroy(); // list sl@0: aPlan.iFlags|=TPlan::EBounded; sl@0: aPlan.iIndex=aIndex; sl@0: return ETrue; sl@0: } sl@0: sl@0: void RDbAccessPlan::EvaluatePlansL() sl@0: // sl@0: // try to find a bounded or index iterator sl@0: // sl@0: { sl@0: TPlan plan; sl@0: // initialise flags sl@0: if (iQuery->HasSearchCondition()) sl@0: plan.iFlags|=TPlan::ERestrict; sl@0: if (iQuery->HasSortSpecification()) sl@0: plan.iFlags|=TPlan::EOrder; sl@0: // find the right type of iterator sl@0: TSglQueIterC indexes(iTable->Def().Indexes().AsQue()); sl@0: for (const CDbTableIndexDef* index;(index=indexes++)!=0;) sl@0: { // only on first column sl@0: TPlan newPlan=plan; sl@0: TBool foundIter=IsBoundedIteratorL(newPlan,index); sl@0: if (!foundIter) sl@0: foundIter=IsIndexIteratorL(newPlan,index); sl@0: else sl@0: EvaluateReorderStage(newPlan,index); sl@0: if (foundIter) sl@0: { sl@0: EvaluateWindowStage(newPlan); sl@0: __LEAVE_IF_ERROR(iPlans.Append(newPlan)); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void RDbAccessPlan::ChoosePlanL(TPlan& aPlan) sl@0: { sl@0: ReducePlans(); sl@0: if (iPlans.Count()==0) sl@0: { sl@0: CreateTableIteratorPlan(aPlan); sl@0: return; sl@0: } sl@0: TPlan::TType type=iPlans[0].Type(); sl@0: if (!iQuery->HasSearchCondition()) sl@0: { sl@0: __ASSERT(type==TPlan::EPlanEF); sl@0: GetSmallestKeySize(aPlan,TPlan::EPlanEF); sl@0: } sl@0: else if (!iQuery->HasSortSpecification()) sl@0: { sl@0: if (type==TPlan::EPlanIJ) sl@0: { sl@0: GetSmallestKeySize(aPlan,TPlan::EPlanIJ); sl@0: TInt r=IndexSpanL(aPlan); sl@0: if (r!=CDbTable::EUnavailableSpan && !iWindow && r>60) sl@0: CreateTableIteratorPlan(aPlan); sl@0: } sl@0: else if (type==TPlan::EPlanOP) sl@0: { sl@0: TInt r=GetTightestRestrictionL(aPlan,TPlan::EPlanOP); sl@0: if (r==CDbTable::EUnavailableSpan) // no index stats available sl@0: aPlan=iPlans[0]; // use first O/P as a guess sl@0: else if ((!iWindow && r>55) || (iWindow && r>60)) sl@0: CreateTableIteratorPlan(aPlan); sl@0: } sl@0: else sl@0: __ASSERT(0); sl@0: } sl@0: else if (type==TPlan::EPlanMN) sl@0: { sl@0: GetSmallestKeySize(aPlan,TPlan::EPlanMN); sl@0: if (iAccess==RDbRowSet::EUpdatable || iWindow) sl@0: aPlan.iFlags|=TPlan::EWindow; sl@0: } sl@0: else if (type==TPlan::EPlanKL) sl@0: { sl@0: GetSmallestKeySize(aPlan,TPlan::EPlanKL); sl@0: TInt r=IndexSpanL(aPlan); sl@0: if (r!=CDbTable::EUnavailableSpan && r>60) sl@0: { // don't use K plan sl@0: if (r<75 || GetSmallestKeySize(aPlan,TPlan::EPlanGH)==KErrNotFound) sl@0: CreateTableIteratorPlan(aPlan); sl@0: } sl@0: } sl@0: else if (type==TPlan::EPlanQR) sl@0: { sl@0: TInt r=GetTightestRestrictionL(aPlan,TPlan::EPlanQR); sl@0: if (r==CDbTable::EUnavailableSpan) // no index stats available sl@0: aPlan=iPlans[0]; // use first Q/R as a guess sl@0: else if (r>60) sl@0: CreateTableIteratorPlan(aPlan); sl@0: } sl@0: else sl@0: { sl@0: __ASSERT(type==TPlan::EPlanGH); sl@0: // don't use this plan without further data, resort to default sl@0: CreateTableIteratorPlan(aPlan); sl@0: } sl@0: } sl@0: sl@0: void RDbAccessPlan::EvaluateWindowStage(TPlan& aPlan) sl@0: { sl@0: if (!iWindow) sl@0: return; sl@0: TUint f=aPlan.iFlags|TPlan::EWindow; sl@0: if (f&TPlan::EReorder) sl@0: f&=~TPlan::EWindow; sl@0: if (f&TPlan::ERestrict) sl@0: f|=TPlan::EWindow; sl@0: if (f&TPlan::EOrder) // order-by stage includes window sl@0: f&=~TPlan::EWindow; sl@0: aPlan.iFlags=f; sl@0: } sl@0: sl@0: TInt RDbAccessPlan::GetTightestRestrictionL(TPlan& aPlan,TPlan::TType aType) sl@0: // sl@0: // aPlan is set to the smallest restricted plan with aType sl@0: // sl@0: { sl@0: TInt span=KMaxTInt; sl@0: TPlan plan; sl@0: for (TInt ii=iPlans.Count();ii--;) sl@0: { sl@0: if (iPlans[ii].Type()!=aType) sl@0: continue; sl@0: TInt t=IndexSpanL(iPlans[ii]); sl@0: if (t==CDbTable::EUnavailableSpan) sl@0: continue; sl@0: if (tKey().Count()Key().Count())) sl@0: { sl@0: span=t; sl@0: plan=iPlans[ii]; sl@0: } sl@0: } sl@0: aPlan=plan; sl@0: return span!=KMaxTInt?span:CDbTable::EUnavailableSpan; sl@0: } sl@0: sl@0: TInt RDbAccessPlan::GetSmallestKeySize(TPlan& aPlan,TPlan::TType aType) sl@0: // sl@0: // aPlan is set to the plan with smallest index with aType sl@0: // sl@0: { sl@0: TInt cols=KMaxTInt; sl@0: TPlan plan; sl@0: for (TInt ii=iPlans.Count();ii--;) sl@0: { sl@0: if (iPlans[ii].Type()!=aType) sl@0: continue; sl@0: __ASSERT(iPlans[ii].iIndex); sl@0: TInt count=iPlans[ii].iIndex->Key().Count(); sl@0: if (countIndexSpanL(*aPlan.iIndex,bounds.iInclusion,bounds.iLower,bounds.iUpper); sl@0: } sl@0: sl@0: void RDbAccessPlan::ReducePlans() sl@0: { sl@0: for (TInt ii=iPlans.Count();--ii>=0;) sl@0: { sl@0: switch (iPlans[ii].Type()) sl@0: { sl@0: default: sl@0: continue; sl@0: case TPlan::EPlanGH: sl@0: if (iWindow) sl@0: iPlans.Remove(ii); // remove Gw/Hw sl@0: break; sl@0: case TPlan::EPlanST: sl@0: iPlans[ii].iFlags|=(TPlan::EReorder|TPlan::EOrder); // convert S/T to Q/R sl@0: EvaluateWindowStage(iPlans[ii]); sl@0: break; sl@0: }; sl@0: } sl@0: // explicit conversion required as GCC can't find the TLinearOrder instantiation sl@0: iPlans.Sort(TLinearOrder(TPlan::OrderByPlan)); sl@0: } sl@0: sl@0: void RDbAccessPlan::CreateTableIteratorPlan(TPlan& aPlan) sl@0: { sl@0: aPlan.iFlags&=~(TPlan::EIndex|TPlan::EBounded); sl@0: if (iQuery->HasSearchCondition()) sl@0: aPlan.iFlags=TPlan::ERestrict; sl@0: if (iQuery->HasSortSpecification()) sl@0: aPlan.iFlags|=TPlan::EOrder; sl@0: EvaluateWindowStage(aPlan); sl@0: } sl@0: sl@0: void RDbAccessPlan::EvaluateReorderStage(TPlan& aPlan,const CDbTableIndexDef* aIndex) sl@0: // sl@0: // for a bounded iter with an order by - can the index be used? sl@0: // sl@0: { sl@0: aPlan.iFlags|=TPlan::EReorder; sl@0: if (!iQuery->HasSortSpecification()) sl@0: return; sl@0: TUint ret=0; sl@0: TRAPD(errCode, ret=FindMatchL(aIndex)); sl@0: if (errCode==KErrNone && ret&EMatch) sl@0: {// do we really need a reorder stage? sl@0: aPlan.iFlags&=~TPlan::EOrder; // don't need to order it sl@0: aPlan.iFlags&=~TPlan::EReorder; // don't need a reorder stage sl@0: if (ret&EReverse) sl@0: aPlan.iFlags|=TPlan::EReverse; sl@0: else sl@0: aPlan.iFlags&=~TPlan::EReverse; sl@0: } sl@0: } sl@0: sl@0: void RDbAccessPlan::PrepareQueryL(CDbTableSource* aSource) sl@0: { sl@0: if (iQuery->HasSearchCondition()) sl@0: { sl@0: CSqlSearchCondition& sc=iQuery->SearchCondition(); sl@0: sc.BindL(aSource->Row()); sl@0: } sl@0: if (iQuery->HasSortSpecification()) sl@0: { sl@0: CDbKey& order=iQuery->SortSpecification(); sl@0: order.SetComparison(iComparison); sl@0: Validate::KeyL(order,iTable->Def().Columns()); sl@0: } sl@0: } sl@0: sl@0: sl@0: void RDbAccessPlan::BuildLC(CDbTableDatabase& aDatabase,RDbRowSet::TAccess aAccess,const TDbWindow& aWindow) sl@0: // sl@0: // Prepare the data pipeline sl@0: // sl@0: { sl@0: __ASSERT(iQuery); sl@0: CDbTableSource* source=TableLC(aDatabase,iQuery->Table()); sl@0: // sl@0: if (aAccess!=RDbRowSet::EInsertOnly) sl@0: { // insert only views do not use Iterators, Restrictions or Windows sl@0: iWindow=aWindow.Size()==aWindow.EUnlimited; sl@0: iAccess=aAccess; sl@0: PrepareQueryL(source); sl@0: EvaluatePlansL(); sl@0: TPlan plan; sl@0: ChoosePlanL(plan); sl@0: source->SetIterator(IteratorL(plan)); sl@0: if (plan.iFlags&TPlan::EReorder) sl@0: Insert(new(ELeave) CDbReorderWindowStage); sl@0: if (plan.iFlags&TPlan::EReverse) sl@0: source->ReverseIteratorL(); sl@0: if (plan.iFlags&TPlan::ERestrict) sl@0: RestrictionL(); sl@0: if (plan.iFlags&TPlan::EOrder) sl@0: OrderByL(source->Row()); sl@0: WindowL(plan,aWindow); sl@0: iPlans.Reset(); sl@0: } sl@0: if (iQuery->HasColumnList()) sl@0: ProjectionL(); sl@0: } sl@0: sl@0: void RDbAccessPlan::BuildLC(CDbTableDatabase& aDatabase,const TDesC& aTable,RDbRowSet::TAccess aAccess) sl@0: { sl@0: CDbTableSource* source=TableLC(aDatabase,aTable); sl@0: if (aAccess!=RDbRowSet::EInsertOnly) sl@0: source->SetIterator(iTable->IteratorL()); sl@0: }