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