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