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