persistentstorage/dbms/pcdbms/utable/UT_QUERY.CPP
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     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 	}