phonebookengines/contactsmodel/cntplsql/src/cplcollectioniterator.cpp
branchRCL_3
changeset 63 f4a778e096c2
child 64 c1e8ba0c2b16
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/cntplsql/src/cplcollectioniterator.cpp	Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,1835 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+/**
+ @file
+ @internalComponent
+ @released
+*/
+
+#include "persistencelayerimpl.h"
+#include "clplcontactproperties.h"
+#include <cntfilt.h>
+#include "cntsqlprovider.h"
+#include "dbsqlconstants.h"
+#include "cntpersistenceutility.h"
+#include "CNTSTD.H"
+#include <sqldb.h>
+
+//
+// The TFindFieldFlags enumeration is duplicated in cviewiterator.h.  It should
+// be refactored into a shared header if possible.
+//
+enum TFindFieldFlags
+	{
+	EFindInAllFields				=0x00000001,
+	EFindFirstName					=0x00000002,
+	EFindLastName					=0x00000004,
+	EFindCompanyName				=0x00000008,
+	EFindInEmailField				=0x00000010,
+	EFindInAnyIdentityField			=0x00000020,
+	EFindFirstNamePronunciation		=0x00000040,
+	EFindLastNamePronunciation		=0x00000080,
+	EFindCompanyNamePronunciation	=0x00000100,
+	EFindInSIPField					=0x00000200
+	};
+
+
+// Maximum number of find iterations to perform in the CPlCollection::FindL()
+// method before returning.
+const TInt KFindIterations = 16;
+
+// These flags must be in the same order as the corresponding fields in
+// RPplIdentityTable::TIdentityField.
+const TFindFieldFlags KNameFlags[] = 
+	{
+	EFindFirstName,
+	EFindLastName,
+	EFindCompanyName,
+	EFindFirstNamePronunciation,
+	EFindLastNamePronunciation,
+	EFindCompanyNamePronunciation
+	};
+
+// Collation level that ignore accents (i.e. a == &auml; ).
+const TInt KCollationLevel= 0;
+
+//
+// The TKeyCmpTextLength class is duplicated in ccontactprivate.cpp.  It should
+// be refactored into shared code/library if possible.
+//
+NONSHARABLE_CLASS(TKeyCmpTextLength) : public TKeyArrayFix
+	{
+public:
+	TKeyCmpTextLength();
+protected:
+	// From TKey.
+	virtual TInt Compare(TInt aLeft,TInt aRight) const;
+	};
+
+
+TKeyCmpTextLength::TKeyCmpTextLength()
+	// Doesn't matter using ECmpNormal, it's ignored.
+	:
+	TKeyArrayFix(0,ECmpNormal,0)
+	{
+	}
+
+
+/**
+Compare the lengths of the words.
+*/
+TInt TKeyCmpTextLength::Compare(TInt aLeft,TInt aRight) const
+	{
+	TDesC* left=(*((TDesC**)At(aLeft)));
+	TDesC* right=(*((TDesC**)At(aRight)));
+	return right->Length()-left->Length();
+	}
+
+	
+/**
+Used as a cleanup item for buffer allocation in CreateFindTextL().
+
+@param aHBufC The buffer to be cleaned up (deleted).
+*/
+GLDEF_C void DestroyHBufC(TAny* aHBufC)
+	{
+	delete *STATIC_CAST(HBufC**, aHBufC);
+	}
+
+
+/**
+Create the "find text", used for the SQL query on the view, from the given text.
+
+@param aText Text to turn into "find text".
+
+@return "Find text" form of the given text.
+*/
+HBufC* CreateFindTextL(const TDesC& aText)
+	{
+	_LIT(KApostrophe, "'");
+	TInt location = aText.Find(KApostrophe);
+
+	HBufC* buf=HBufC::NewL(aText.Length()+2);
+	TPtr ptr=buf->Des();
+	ptr.Zero();
+	ptr.Append('%');
+	ptr += aText;
+	ptr.Append('%');
+	
+	// Insert additional apostrophes if required.  This is so the SQL search
+	// string behaves correctly.
+	if(location != KErrNotFound)
+		{
+		CleanupStack::PushL(buf);
+
+		TPtrC rightBuf = *buf;		
+		HBufC* leftBuf=HBufC::NewL(0);
+		CleanupStack::PushL(TCleanupItem(DestroyHBufC, &leftBuf));
+
+		// Increment location because we have added the * character.
+		location++;
+		
+		while (location != KErrNotFound)
+			{
+			// Copy left hand string up to the first apostrophe into a new
+			// buffer and append an apostrophe.
+			leftBuf = leftBuf->ReAllocL(leftBuf->Length()+location+2); 
+			TPtr ptrLeftBuf = leftBuf->Des();
+			ptrLeftBuf.Append(rightBuf.Left(location+1));
+			ptrLeftBuf += (KApostrophe);
+
+			// Make a copy of the right hand part.
+			TInt rightLength = rightBuf.Length()-location-1;
+			rightBuf.Set(rightBuf.Right(rightLength));
+			
+			// Search for another apostrophe.
+			location = rightBuf.Find(KApostrophe);
+			}
+		
+		// Now append the rest of the right hand part.
+		leftBuf = leftBuf->ReAllocL(leftBuf->Length()+rightBuf.Length()); 
+		TPtr ptrLeftBuf = leftBuf->Des();
+		ptrLeftBuf.Append(rightBuf);
+
+		CleanupStack::Pop(&leftBuf);	
+		CleanupStack::PopAndDestroy(buf);
+		
+		return (leftBuf);
+		}	
+	
+	return (buf);	
+	}
+
+
+/**
+For the given field type UID, increase aIdentityColumnsCount if the field maps
+to one of the columns in the Identity table and add the relevant find flag.
+
+@param aUid Field type UID.
+@param aFindFlags Updated with find flag which maps to the given field type UID.
+@param aIdentityColumnsCount Incremented if the field type UID maps to a column
+in the Identity table.
+*/
+//
+// This method is duplicated in cviewiterator.cpp.  It should be refactored into
+// shared code/library if possible.
+//
+void SetFindFlagsAndColumnsCount(TInt32 aUid,TInt& aFindFlags,TInt& aIdentityColumnsCount)
+	{
+	switch(aUid)
+		{
+		case KUidContactFieldGivenNameValue:
+			{
+			++aIdentityColumnsCount;
+			aFindFlags |= EFindFirstName;
+			break;
+			}
+		case KUidContactFieldFamilyNameValue:
+			{
+			++aIdentityColumnsCount;
+			aFindFlags |= EFindLastName;
+			break;
+			}
+		case KUidContactFieldCompanyNameValue:
+			{
+			++aIdentityColumnsCount;
+			aFindFlags |= EFindCompanyName;
+			break;
+			}
+		case KUidContactFieldGivenNamePronunciationValue:
+			{
+			++aIdentityColumnsCount;
+			aFindFlags |= EFindFirstNamePronunciation;
+			break;
+			}
+		case KUidContactFieldFamilyNamePronunciationValue:
+			{
+			++aIdentityColumnsCount;
+			aFindFlags |= EFindLastNamePronunciation;
+			break;
+			}
+		case KUidContactFieldCompanyNamePronunciationValue:
+			{
+			++aIdentityColumnsCount;
+			aFindFlags |= EFindCompanyNamePronunciation;
+			break;
+			}
+		case KUidContactFieldEMailValue:
+			{
+			aFindFlags |= EFindInEmailField;
+			break;
+			}
+		case KUidContactFieldSIPIDValue:
+			{
+			aFindFlags |= EFindInSIPField;
+			break;			
+			}
+		case KUidContactFieldMatchAllValue:
+			{
+			//added to address issues raised in INC049017
+			//needed as a seperate case instead of modifying the default value because Identitys should not always be searched
+			//if a valid KUid is used. e.g.: KUidContactFieldAddress. If the default value was modified and someone wanted to
+			//perform an address search using Elizabeth (as in elizabeth road) contacts of that name would also be found.
+			aFindFlags |= EFindInAllFields|EFindInAnyIdentityField;
+			break;
+			}
+		default:
+			aFindFlags |= EFindInAllFields;
+		}
+	}
+
+
+/**
+Determine if the Identity table requires to be searched for the given find
+flags.
+
+@param aFindFlags Set of find flags describing which fields will be searched.
+
+@return ETrue If one of the flags in aFindFlags maps to a column in the Identity
+table, EFalse otherwise.
+*/
+//
+// This method is duplicated in cviewiterator.cpp.  It should be refactored into
+// shared code/library if possible.
+//
+TBool SearchIdentityFieldsRequired(TInt aFindFlags)
+	{
+	return aFindFlags &
+		( EFindInAnyIdentityField | EFindFirstName | EFindLastName | EFindCompanyName |
+			EFindFirstNamePronunciation | EFindLastNamePronunciation | EFindCompanyNamePronunciation);
+	}
+
+
+/**
+Determine if only the Identity table requires to be searched for the given find
+flags.
+
+@param aFindFlags Set of find flags describing which fields will be searched.
+
+@return ETrue If one of the flags in aFindFlags maps to a column in the Identity
+table and no columns in any other table, EFalse otherwise.
+*/
+//
+// This method is duplicated in cviewiterator.cpp.  It should be refactored into
+// shared code/library if possible.
+//
+TBool CPlCollection::UsesIdentityFieldsOnly(TInt aFindFlags)
+	{
+	return (aFindFlags & (EFindFirstName | EFindLastName | EFindCompanyName |
+			EFindFirstNamePronunciation |EFindLastNamePronunciation |EFindCompanyNamePronunciation) ) &&
+		! (aFindFlags & (EFindInAllFields | EFindInEmailField | EFindInSIPField) );
+	}
+
+
+/**
+Update a set of find flags and an Identity table column count from the field
+type UIDs in the given field definition.
+
+@param aFindFlags Updated with those flags which map to the field type UIDs in
+aFieldDef.
+@param aIdentityColumnsCount Updated with the number of field type UIDs in
+aFieldDef which map to columns in the Identity table.
+@param aFieldDef Field definition from which to create set of find flags and
+Identity table column count.
+*/
+//
+// This method is duplicated in cviewiterator.cpp.  It should be refactored into
+// shared code/library if possible.
+//
+void ConstructBitwiseFindFlags(TInt& aFindFlags,TInt& aIdentityColumnsCount,const CContactItemFieldDef* aFieldDef)
+	{
+	if(aFieldDef!=NULL && aFieldDef->Count()>0)
+		{
+		for(TInt ii = 0;ii < aFieldDef->Count();ii++)
+			{
+			SetFindFlagsAndColumnsCount(aFieldDef->At(ii).iUid,aFindFlags,aIdentityColumnsCount);
+			}
+		}
+	else
+		{
+		aFindFlags |= EFindInAllFields|EFindInAnyIdentityField;
+		}
+	}
+
+
+/**
+Update a set of find flags and an Identity table column count from the field
+type UIDs in the given text definition.  This can be used to tell the find
+method what tables need to be searched for a given text definition.  If the text
+definition is NULL we search in all tables.
+
+@param aFindFlags Updated with those flags which map to the field type UIDs in
+aTextDef.
+@param aIdentityColumnsCount Updated with the number of field type UIDs in
+aTextDef which map to columns in the Identity table.
+@param aTextDef Text definition from which to create set of find flags and
+Identity table column count.
+*/
+//
+// This method is duplicated in cviewiterator.cpp.  It should be refactored into
+// shared code/library if possible.
+//
+void CPlCollection::ConstructBitwiseFlagsFromTextDef(TInt& aFindFlags,TInt& aIdentityColumnsCount,const CContactTextDef* aTextDef)
+	{
+	if(aTextDef != NULL && aTextDef->Count()>0)
+		{
+		for(TInt ii = 0;ii < aTextDef->Count();ii++)
+			{
+			SetFindFlagsAndColumnsCount(aTextDef->At(ii).iFieldType.iUid,aFindFlags,aIdentityColumnsCount);
+			}
+		TFieldType fallback = aTextDef->FallbackField();
+		if (fallback != KUidContactFieldNone)
+		SetFindFlagsAndColumnsCount(fallback.iUid,aFindFlags,aIdentityColumnsCount);
+		}
+	else
+		{
+		aFindFlags |= EFindInAllFields|EFindInAnyIdentityField;
+		}
+	}
+
+
+/**
+Utility method used to search a contact id in contact database.
+
+@param aReqId requested contact id to look for
+@param aId out parameter; will be filled with the actual found contact item id 
+@param aContactType specifies contact type to be search
+@param aDeleted set to ETrue if a search through deleted contacts is required
+
+@return ETrue if a contact item with contact id greater or equal with aReqId exists in contact database
+		EFalse otherwise
+*/
+TBool CPlCollection::SeekContactL(TContactItemId aReqId,TContactItemId& aId,TUid& aContactType, TBool& aDeleted)
+	{
+	TBool ret = ETrue;
+
+	HBufC* selectString = HBufC::NewLC(KSelectTwoFieldsWithGreater().Length() + 
+									KContactId().Length() + 
+									KContactTypeFlags().Length() + 
+									KSqlContactTableName().Length() + 					
+									KContactId().Length() + 3); 
+	TPtr ptrSelectString = selectString->Des();
+	ptrSelectString.Format(KSelectTwoFieldsWithGreater, &KContactId, &KContactTypeFlags, &KSqlContactTableName, &KContactId, aReqId);
+
+	RSqlStatement selectStatement;
+	CleanupClosePushL(selectStatement);
+		
+	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), ptrSelectString));
+
+	const TInt idIndex = selectStatement.ColumnIndex(KContactId);
+	User::LeaveIfError(idIndex);
+	const TInt typeIndex = selectStatement.ColumnIndex(KContactTypeFlags);
+	User::LeaveIfError(typeIndex);
+	TInt err;
+	if((err = selectStatement.Next()) == KSqlAtRow) 
+		{
+		aId = selectStatement.ColumnInt(idIndex);
+		TInt typeFlags = selectStatement.ColumnInt(typeIndex);
+		aContactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags); 
+		TInt attr = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift; 
+		aDeleted = (attr == EContactAttrsFlags_Deleted);
+		}
+	else 
+		{
+		User::LeaveIfError(err);
+		ret = EFalse;	
+		}
+	
+	CleanupStack::PopAndDestroy(2, selectString); //selectStatement, selectString	
+	return ret;
+	}
+	
+/**
+CPlCollection constructor.
+
+@param aContactsFile Contacts file object from the Persistence Layer.
+*/
+CPlCollection::CPlCollection(CPplContactsFile& aContactsFile)
+	: 
+	iContactsFile( aContactsFile ), iRSqlstatementsWorking( EFalse )
+	{
+	}
+	
+/**
+CPlCollection ConstructL
+*/	
+void CPlCollection::ConstructL()
+	{
+	TCntSqlStatementType statementType(ESelect, KSqlContactTableName);
+	iSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
+	}
+	
+/**
+CPlCollection NewL
+*/		
+CPlCollection* CPlCollection::NewL(CPplContactsFile& aContactsFile)
+	{
+	CPlCollection* self = new (ELeave) CPlCollection(aContactsFile);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+
+/**
+CPlCollection destructor.
+*/
+CPlCollection::~CPlCollection()
+	{
+	Reset();
+	delete iSelectStatement;
+	iSelectStatement = NULL;
+	}
+
+
+/**
+Get the count of contacts in the Contacts table.
+
+@return Count of contacts in the Contacts table.
+*/
+TInt CPlCollection::ContactCountL()
+	{
+	TInt count = 0;
+
+	//count contact cards
+	HBufC* selectString = HBufC::NewLC(KCountTypeSelect().Length() + 
+						KSqlContactTableName().Length() + KContactTypeFlags().Length() + KContactTypeFlags().Length() + 6); 
+	TPtr ptrSelectString = selectString->Des();
+	ptrSelectString.Format(KCountTypeSelect, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_ContactCard,
+							&KContactTypeFlags, EContactAttributes_Shift, EContactAttrsFlags_Deleted);
+
+	TSqlScalarFullSelectQuery scalarQuery(iContactsFile.NamedDatabase());
+	
+	count = scalarQuery.SelectIntL(ptrSelectString);
+	CleanupStack::PopAndDestroy(selectString);
+
+	//count own card
+	selectString = HBufC::NewLC(KCountTypeSelect().Length() + 
+				KSqlContactTableName().Length() + KContactTypeFlags().Length() + KContactTypeFlags().Length() + 6); 
+	ptrSelectString = selectString->Des();
+	ptrSelectString.Format(KCountTypeSelect, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_OwnCard,
+							&KContactTypeFlags, EContactAttributes_Shift, EContactAttrsFlags_Deleted);
+	
+	count += scalarQuery.SelectIntL(ptrSelectString);
+	CleanupStack::PopAndDestroy(selectString);
+	
+	//count groups
+	selectString = HBufC::NewLC(KCountTypeSelect().Length() + 
+				KSqlContactTableName().Length() + KContactTypeFlags().Length() + KContactTypeFlags().Length() + 6); 
+	ptrSelectString = selectString->Des();
+	ptrSelectString.Format(KCountTypeSelect, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_Group,
+							&KContactTypeFlags, EContactAttributes_Shift, EContactAttrsFlags_Deleted);
+	
+	count += scalarQuery.SelectIntL(ptrSelectString);
+	CleanupStack::PopAndDestroy(selectString);
+	
+	//card template
+	selectString = HBufC::NewLC(KCountTypeSelect().Length() + 
+				KSqlContactTableName().Length() + KContactTypeFlags().Length() + KContactTypeFlags().Length() + 6); 
+	ptrSelectString = selectString->Des();
+	ptrSelectString.Format(KCountTypeSelect, &KSqlContactTableName, &KContactTypeFlags, EContactType_Shift, EContactTypeFlags_CardTemplate,
+							&KContactTypeFlags, EContactAttributes_Shift, EContactAttrsFlags_Deleted);
+	
+	count += scalarQuery.SelectIntL(ptrSelectString);
+	CleanupStack::PopAndDestroy(selectString);
+			
+	return count;
+	}
+
+
+/**
+Get a collection of contact IDs using the specified view/collection parameters.
+
+@param aViewType Type of view/collection.
+@param aTime Used if view/collection type is "changed since".
+@param aGuid Used if view/collection type is "find GUID".
+
+@return Contact ID array of those contacts which match the specified collection
+parameters.
+*/
+CContactIdArray* CPlCollection::CollectionL(TLplViewType aViewType,TTime aTime,const TDesC& aGuid)
+	{
+	CContactIdArray* idArray=NULL;
+	switch(aViewType)
+		{
+		case EChangedSince :
+			{
+			idArray = ChangedSinceL(aTime);
+			}
+			break;
+		case EDeleted :
+			{
+			idArray = DeletedL();
+			}
+			break;
+		case EUnfiled :
+			{
+			idArray = UnfiledL();
+			}
+			break;
+		case EFindGuid :
+			{
+			idArray = GuidL(aGuid);
+			}
+			break;
+		default:
+			{
+			User::Leave(KErrNotFound);
+			}
+			break;
+		}
+	return idArray;
+	}
+
+	
+/**
+Utility method used to serach hint field for provided contact id
+
+@param aBitWiseFileter filter used for hint matching
+@param aContactId contact item id
+
+@return ETrue if a hint is found 
+		EFalse otherwise
+*/	
+TBool CPlCollection::ContactMatchesHintFieldL(TInt aBitWiseFilter, TContactItemId aContactId)
+	{
+	TBool hintMatch = EFalse;
+	
+	HBufC* searchCond = HBufC::NewLC(KConditionClause().Length() + KContactId().Length() + 32);
+	searchCond->Des().Format(KConditionClause, &KContactId, aContactId);
+
+	RSqlStatement selectStatement;
+	CleanupClosePushL(selectStatement);
+		
+	iSelectStatement->Reset();	
+	iSelectStatement->SetParamL(KContactId, KSpace);
+	iSelectStatement->SetParamL(KContactTypeFlagsParam, KSpace);
+	iSelectStatement->SetConditionL(*searchCond);
+	
+	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+
+	TInt err;
+	if((err = selectStatement.Next()) == KSqlAtRow)
+		{
+		const TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
+		TInt typeFlags = selectStatement.ColumnInt(typeFlagsIndex);
+		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
+		if (iContactsFile.ContactProperties().CheckType(contactType))
+			{
+			TInt hint = typeFlags & EContactHintFlags_Mask;
+			hintMatch = HintFieldMatchesFilter(hint, aBitWiseFilter);	
+			}
+		}
+	else
+		{
+		User::LeaveIfError(err);
+		}	
+	
+	CleanupStack::PopAndDestroy(2, searchCond); //searchCond, selectStatement
+	return hintMatch;
+	}
+
+/**
+Utility method used for phone matching
+
+@param aNumber phone number to be matched
+@param aMatchLengthFromRight specifies the number of relevant characters to be matched
+@return array with contact ids matching passed phone number
+*/
+CContactIdArray* CPlCollection::MatchPhoneNumberL(const TDesC& aNumber, const TInt aMatchLengthFromRight)
+	{
+	return iContactsFile.FieldMatcher().MatchPhoneNumberL(aNumber, aMatchLengthFromRight);
+	}
+
+
+/**
+Get a collection of contact IDs which have the given GUID.  Since GUIDs are
+unique (i.e. no two contacts can have the same GUID) there will only ever be
+one contact ID in this collection.
+
+@param aGuid Contact GUID.
+
+@return Contact ID array containing the contact with the given GUID.
+*/
+CContactIdArray* CPlCollection::GuidL(const TDesC& aGuid)
+	{
+	// Create the database query string.
+	TBuf<256> searchCond;
+	_LIT(KFormat,"%S = '%S'");
+	searchCond.Format(KFormat, &KContactGuidString, &aGuid);
+
+	RSqlStatement selectStatement;
+	CleanupClosePushL(selectStatement);
+		
+	iSelectStatement->Reset();	
+	iSelectStatement->SetParamL(KContactId, KSpace);
+	iSelectStatement->SetConditionL(searchCond);
+	
+	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+
+	CContactIdArray* array = CContactIdArray::NewL();
+	CleanupStack::PushL(array);
+	
+	TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
+	TInt err;
+	while((err = selectStatement.Next()) == KSqlAtRow)
+		{
+		array->AddL(selectStatement.ColumnInt(idIndex));	
+		}
+
+	if(err != KSqlAtEnd)
+		{
+		User::LeaveIfError(err);	
+		}
+		
+	CleanupStack::Pop(array);
+	CleanupStack::PopAndDestroy(&selectStatement);
+	
+	return array;
+	}
+
+
+/**
+Get a collection of contact IDs which have changed since the given time.
+
+@param aTime Changed since time.
+
+@return Contact ID array of those contacts which have changed since the given
+time.
+*/
+CContactIdArray* CPlCollection::ChangedSinceL(TTime aTime)
+	{
+	// Create the database query string.
+	_LIT(KFormat,"%S >= %LD or %S >= %LD");
+	HBufC* searchCond = HBufC::NewLC(KFormat().Length()+
+		KContactCreationDate().Length()+KContactLastModified().Length()+
+		2 * 64);
+
+	TPtr ptr = searchCond->Des();
+	ptr.Format(KFormat, &KContactCreationDate, aTime.Int64(), &KContactLastModified, aTime.Int64());
+
+	RSqlStatement selectStatement;
+	CleanupClosePushL(selectStatement);
+		
+	iSelectStatement->Reset();	
+	iSelectStatement->SetParamL(KContactId, KSpace);
+	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+	iSelectStatement->SetConditionL(*searchCond);
+	
+	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+
+	CContactIdArray* array = CContactIdArray::NewL();
+	CleanupStack::PushL(array);
+
+	const TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
+	const TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
+	TInt err;
+
+	// Iterate through the view and include only those contacts of the desired
+	// type (as determined by CheckType()).
+	while((err = selectStatement.Next()) == KSqlAtRow)
+		{
+		TInt typeFlags = selectStatement.ColumnInt(typeFlagsIndex);
+		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
+		if (iContactsFile.ContactProperties().CheckType(contactType))
+			{
+			array->AddL(selectStatement.ColumnInt(idIndex));		
+			}
+		}
+
+	if(err != KSqlAtEnd)
+		{
+		User::LeaveIfError(err);
+		}
+		
+	CleanupStack::Pop(array);
+	CleanupStack::PopAndDestroy(2,searchCond); // searchCond, selectStatement
+
+	return array;
+	}
+
+
+/**
+Get a collection of contact IDs which are 'unfiled'.
+
+@return Contact ID array of those contacts which are 'unfiled'.
+*/
+CContactIdArray* CPlCollection::UnfiledL()
+	{
+	RSqlStatement selectStmt;
+	CleanupClosePushL(selectStmt);
+		
+	iSelectStatement->Reset();	
+	iSelectStatement->SetParamL(KContactId, KSpace);
+	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+	
+    User::LeaveIfError(selectStmt.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+
+	CContactIdArray* array = CContactIdArray::NewL();
+	CleanupStack::PushL(array);
+	
+	TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
+	TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
+
+	// for WHERE contact_group_member_id = [contact id value]
+	const TInt KWhereMemberClauseBufSize(KGroupContactGroupMemberId().Size() + KWhereStringEqualsStringFormatText().Size() + KGroupContactGroupMemberIdParam().Size() );
+	HBufC* whereMemberIdClause = HBufC::NewLC(KWhereMemberClauseBufSize);
+	whereMemberIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText, &KGroupContactGroupMemberId, &KGroupContactGroupMemberIdParam );
+	
+	// select group id
+	// For a statement in the following format:
+	// 	SELECT contact_group_id FROM groups 
+	//		WHERE contact_group_member_id = [contact id value];
+	//
+	TCntSqlStatementType statementType(ESelect, KSqlContactGroupTableName);
+	CCntSqlStatement* selectGroupsStmnt = TSqlProvider::GetSqlStatementL(statementType);
+	CleanupStack::PushL(selectGroupsStmnt);
+	selectGroupsStmnt->SetParamL(KGroupContactGroupId(), KNullDesC() );
+	selectGroupsStmnt->SetConditionL(*whereMemberIdClause);
+	const TInt KGroupContactGroupMemberIdParamIndex(KFirstIndex); // second parameter in the query
+
+	TInt err;
+	while((err = selectStmt.Next()) == KSqlAtRow)
+		{
+		TInt typeFlags = selectStmt.ColumnInt(typeFlagsIndex);
+		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
+		TInt contactAttrib = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift;
+		
+		if (contactAttrib & CContactItem::EDeleted)
+			{
+			continue;
+			}
+			
+		if (contactType == KUidContactCard || contactType == KUidContactOwnCard)
+			{
+			TInt contactId = selectStmt.ColumnInt(idIndex);
+            			
+        	RSqlStatement selectGroupSqlStmt;
+        	CleanupClosePushL(selectGroupSqlStmt);
+        	
+        	selectGroupSqlStmt.PrepareL(iContactsFile.NamedDatabase(), selectGroupsStmnt->SqlStringL() );
+        	User::LeaveIfError(selectGroupSqlStmt.BindInt(KGroupContactGroupMemberIdParamIndex, contactId));
+        	if((err = selectGroupSqlStmt.Next()) == KSqlAtEnd)
+        	    {
+        	    //add the contact id which is not in any group
+    			array->AddL(contactId);
+        	    }
+        	    
+        	User::LeaveIfError(err);    
+        	CleanupStack::PopAndDestroy(&selectGroupSqlStmt); 
+			}
+		}
+
+	if(err != KSqlAtEnd)
+		{
+		User::LeaveIfError(err);
+		}
+		
+	CleanupStack::PopAndDestroy(2, whereMemberIdClause);  //whereMemberIdClause, selectGroupsStmnt #
+	CleanupStack::Pop(array);
+	CleanupStack::PopAndDestroy(&selectStmt);
+	return array;
+	}
+
+
+/**
+Get a collection of contact IDs which are marked as deleted.
+
+@return Contact ID array of those contacts which are marked as deleted.
+*/
+CContactIdArray* CPlCollection::DeletedL()
+	{
+	RSqlStatement selectStatement;
+	CleanupClosePushL(selectStatement);
+		
+	iSelectStatement->Reset();	
+	iSelectStatement->SetParamL(KContactId, KSpace);
+	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+
+	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+	
+	CContactIdArray* array = CContactIdArray::NewL();
+	CleanupStack::PushL(array);
+	
+	TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
+	TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
+	TInt err;
+	while((err = selectStatement.Next()) == KSqlAtRow)
+		{
+		TInt typeFlags = selectStatement.ColumnInt(typeFlagsIndex);
+		TInt contactAttrib = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift;
+		
+		if (contactAttrib & CContactItem::EDeleted)
+			{
+			array->AddL(selectStatement.ColumnInt(idIndex));
+			}			
+		}
+	
+	if(err != KSqlAtEnd)
+		{
+		User::LeaveIfError(err);	
+		}
+	
+	CleanupStack::Pop(array);
+	CleanupStack::PopAndDestroy(&selectStatement); 
+
+	return array;
+	}
+
+
+/**
+Perform a synchronous find for the given text and field definition.
+
+@param aText Text to find.
+@param aFieldDef Field definition to use.
+@param aSessionID
+
+@return Array of contact IDs resulting from the search.
+*/
+CContactIdArray* CPlCollection::FindL(const TDesC& aText, const CContactItemFieldDef* aFieldDef, TUint aSessionId)
+	{
+	CContactIdArray* idsFound = CContactIdArray::NewL();
+	CleanupStack::PushL(idsFound);
+
+	// Create the "find text" from the given text.
+	HBufC *findText = CreateFindTextL(aText);
+	CleanupStack::PushL(findText);
+
+	// Find out what tables need to included in the search as determined by the
+	// given field definition.
+	TInt findFlags = 0;
+	TInt identityTableFieldsCount = 0;
+	ConstructBitwiseFindFlags(findFlags,identityTableFieldsCount,aFieldDef);
+	
+	// Search through the first/last name (and their pronunciation) and company
+	// names fields in the Identity table.
+	if ( SearchIdentityFieldsRequired(findFlags) )
+		{
+		_LIT(KWhereClause,"(%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S')");
+		HBufC* searchCond = HBufC::NewLC(KWhereClause().Length() +
+								KContactFirstName().Length() + findText->Length() +
+								KContactLastName().Length() + findText->Length() +
+								KContactCompanyName().Length() + findText->Length() +
+								KContactFirstNamePrn().Length() + findText->Length() +
+								KContactLastNamePrn().Length() + findText->Length() +
+								KContactCompanyNamePrn().Length() + findText->Length());
+		searchCond->Des().Format(KWhereClause, &KContactFirstName, findText,
+								&KContactLastName, findText, &KContactCompanyName, findText,
+								&KContactFirstNamePrn, findText, &KContactLastNamePrn, findText,
+								&KContactCompanyNamePrn, findText);
+			
+		RSqlStatement selectStatement;
+		CleanupClosePushL(selectStatement);
+		
+		iSelectStatement->Reset();	
+		iSelectStatement->SetParamL(KContactId, KSpace);
+		iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+		iSelectStatement->SetParamL(KContactFirstName, KSpace);
+		iSelectStatement->SetParamL(KContactLastName, KSpace);
+		iSelectStatement->SetParamL(KContactCompanyName, KSpace);
+		iSelectStatement->SetParamL(KContactFirstNamePrn, KSpace);
+		iSelectStatement->SetParamL(KContactLastNamePrn, KSpace);
+		iSelectStatement->SetParamL(KContactCompanyNamePrn, KSpace);
+		iSelectStatement->SetConditionL(*searchCond);
+		
+		User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+		
+		while(PerformFindIterationL(idsFound, aText, selectStatement, findFlags, aSessionId)) 
+			{
+			// Keep performing find iteration until EFalse is returned.
+			}
+		
+		CleanupStack::PopAndDestroy(2, searchCond); // searchCond, selectStatement
+		}
+
+	// Search through the email address fields
+	if (findFlags & (EFindInAllFields | EFindInEmailField))
+		{
+		TCntSqlStatementType statementType(ESelect, KSqlContactCommAddrTableName);
+		CCntSqlStatement* cntSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
+		CleanupStack::PushL(cntSelectStatement);
+		
+		_LIT(KWhereClause, "(%S = %d) AND (%S LIKE '%S')");
+		HBufC* searchCond = HBufC::NewLC(KWhereClause().Length()+ 
+			KCommAddrType().Length() + 
+			KCommAddrValue().Length() + findText->Length());
+		searchCond->Des().Format(KWhereClause, 
+			&KCommAddrType, CPplCommAddrTable::EEmailAddress, 
+			&KCommAddrValue, findText);
+		
+		RSqlStatement selectStatement;
+		CleanupClosePushL(selectStatement);
+		
+		cntSelectStatement->SetParamL(KContactId, KSpace);
+		cntSelectStatement->SetConditionL(*searchCond);
+
+		User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), cntSelectStatement->SqlStringL()));
+		
+		while(PerformIdFindIterationL(idsFound, selectStatement))
+			{
+			// Keep performing find iteration until EFalse is returned.
+			}
+			
+		CleanupStack::PopAndDestroy(3, cntSelectStatement); //selectStatement, searchCond, cntSelectStatement
+		}
+
+	// Search through the sip address fields
+	if (findFlags & (EFindInAllFields | EFindInSIPField))
+		{
+		TCntSqlStatementType statementType(ESelect, KSqlContactCommAddrTableName);
+		CCntSqlStatement* cntSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
+		CleanupStack::PushL(cntSelectStatement);
+		
+		_LIT(KWhereClause, "(%S = %d) AND (%S LIKE '%S')");
+		HBufC* searchCond = HBufC::NewLC(KWhereClause().Length()+ 
+			KCommAddrType().Length() + 
+			KCommAddrValue().Length() + findText->Length());
+		searchCond->Des().Format(KWhereClause, 
+			&KCommAddrType, CPplCommAddrTable::ESipAddress, 
+			&KCommAddrValue, findText);
+		
+		RSqlStatement selectStatement;
+		CleanupClosePushL(selectStatement);
+		
+		cntSelectStatement->SetParamL(KContactId, KSpace);
+		cntSelectStatement->SetConditionL(*searchCond);
+
+		User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), cntSelectStatement->SqlStringL()));
+		
+		while(PerformIdFindIterationL(idsFound, selectStatement))
+			{
+			// Keep performing find iteration until EFalse is returned.
+			}
+			
+		CleanupStack::PopAndDestroy(3, cntSelectStatement); //selectStatement, searchCond, cntSelectStatement
+		}
+		
+	// Search through the searchable text for any other fields.
+	if (findFlags & EFindInAllFields)
+		{
+		iSelectStatement->Reset();
+		iSelectStatement->SetParamL(KContactId, KSpace);
+		iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+		iSelectStatement->SetParamL(KContactTextFieldHeader, KSpace);
+		iSelectStatement->SetParamL(KContactTextFields, KSpace);
+		
+		RSqlStatement selectStatement;
+		CleanupClosePushL(selectStatement);
+	
+		User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+
+ 		while(FindL(idsFound,*findText,aFieldDef, selectStatement, aSessionId))
+			{
+			// Keep performing find iteration until EFalse is returned.
+			}
+		
+		CleanupStack::PopAndDestroy(&selectStatement);
+		}
+
+	CleanupStack::PopAndDestroy(findText);
+	CleanupStack::Pop(idsFound);
+
+	return(idsFound);
+	}
+
+
+/**
+Get a collection of contact IDs which match the given filter.
+
+@param aFilter Filter to match.
+
+@return Contact ID array of those contacts which match the given filter.
+*/
+CContactIdArray* CPlCollection::FilterDatabaseL(CCntFilter& aFilter)
+	{
+	_LIT(KWhereCondition,"%S >= %LD");
+
+	iSelectStatement->Reset();
+	iSelectStatement->SetParamL(KContactId, KSpace);
+	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+
+	if (aFilter.IncludeModifiedContacts() || aFilter.IncludeDeletedContacts())
+		{
+		// Create query to search for modified/deleted contacts.
+		HBufC* searchCond=HBufC::NewLC(KWhereCondition().Length() + 
+			KContactLastModified().Length() + 64); 
+			
+		TPtr ptr=searchCond->Des();
+		ptr.Format(KWhereCondition, &KContactLastModified, aFilter.GetFilterDateTime().Int64());
+	
+		iSelectStatement->SetConditionL(*searchCond);
+			
+		CleanupStack::PopAndDestroy(searchCond);	
+		}
+	else if (aFilter.IncludeNewContacts())
+		{
+		// Create query to search for inserted contacts.
+		HBufC* searchCond=HBufC::NewLC(KWhereCondition().Length() +
+			KContactCreationDate().Length() + 64);
+
+		TPtr ptr=searchCond->Des();
+		ptr.Format(KWhereCondition, &KContactCreationDate, aFilter.GetFilterDateTime().Int64());
+		
+		iSelectStatement->SetConditionL(*searchCond);
+		
+		CleanupStack::PopAndDestroy(searchCond);
+		}
+
+	RSqlStatement selectStatement;
+	CleanupClosePushL(selectStatement);
+	
+	const TInt idIndex = iSelectStatement->ParameterIndex(KContactId);
+	const TInt typeFlagsIndex = iSelectStatement->ParameterIndex(KContactTypeFlags);
+
+	TBool filterIncludesAllContacts = !(aFilter.IncludeDeletedContacts() ||
+		aFilter.IncludeNewContacts() || aFilter.IncludeModifiedContacts());
+
+	CContactIdArray* idArray = CContactIdArray::NewL();
+	CleanupStack::PushL(idArray);
+
+	User::LeaveIfError(selectStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+		
+	TInt err;
+	while((err = selectStatement.Next()) == KSqlAtRow)
+		{
+		TInt typeFlags = selectStatement.ColumnInt(typeFlagsIndex);
+		
+		TUid type = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
+		TUint32 attribs = (typeFlags & EContactAttributes_Mask) >> EContactAttributes_Shift;
+
+		if (((aFilter.IncludeDeletedContacts() && (attribs & CContactItem::EDeleted)) 
+		||  (aFilter.IncludeNewContacts() 
+		||   aFilter.IncludeModifiedContacts()) && (aFilter.TestContactFilterType(type)))
+		|| (filterIncludesAllContacts && aFilter.TestContactFilterType(type))) 
+			{
+			TContactItemId id = selectStatement.ColumnInt(idIndex);
+			idArray->AddL(id);
+			}
+		}
+		
+	if(err != KSqlAtEnd)
+		{
+		User::LeaveIfError(err);
+		}
+
+	CleanupStack::Pop(idArray);
+	CleanupStack::PopAndDestroy(&selectStatement);
+	
+	return idArray;
+	}
+
+
+/**
+Perform a find interation based on given sql statement for the given text.
+
+@param aIdsFound On return the contact IDs found.
+@param aText Text to find.
+@param aStatement sql statement
+@param aFieldsToSearch Fields within the view to search.
+@param aSessionId Session ID (only relevant for ICC contacts).
+
+@return ETrue if further iterations are required (i.e. view has not been fully
+evaluated and searched), EFalse otherwise.
+*/
+TBool CPlCollection::PerformFindIterationL(CContactIdArray* aIdsFound,const TDesC& aText,RSqlStatement aStatement,  TInt aFieldsToSearch, TUint aSessionId)
+	{
+	TContactItemId contactId;
+
+	const TInt idIndex = aStatement.ColumnIndex(KContactId);
+	User::LeaveIfError(idIndex);
+	const TInt typeFlagsIndex = aStatement.ColumnIndex(KContactTypeFlags);
+	User::LeaveIfError(typeFlagsIndex);
+	TInt err;
+	
+	const TInt firstNameIndex = aStatement.ColumnIndex(KContactFirstName);
+	User::LeaveIfError(firstNameIndex);
+	const TInt lastNameIndex = aStatement.ColumnIndex(KContactLastName);
+	User::LeaveIfError(lastNameIndex);
+	const TInt companyNameIndex = aStatement.ColumnIndex(KContactCompanyName);
+	User::LeaveIfError(companyNameIndex);
+	const TInt firstNamePrnIndex = aStatement.ColumnIndex(KContactFirstNamePrn);
+	User::LeaveIfError(firstNamePrnIndex);
+	const TInt lastNamePrnIndex = aStatement.ColumnIndex(KContactLastNamePrn);
+	User::LeaveIfError(lastNamePrnIndex);
+	const TInt companyNamePrnIndex = aStatement.ColumnIndex(KContactCompanyNamePrn);
+	User::LeaveIfError(companyNamePrnIndex);
+	
+	while((err = aStatement.Next()) == KSqlAtRow)
+		{
+		// Do not include contact if it is not of the desired type.
+		TInt typeFlags = aStatement.ColumnInt(typeFlagsIndex);
+		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
+
+		if(iContactsFile.ContactProperties().CheckType(contactType) == EFalse)
+			{
+			continue;
+			}
+
+		contactId = aStatement.ColumnInt(idIndex);
+
+		// Check that the contact is not already present in the given contact
+		// IDs before searching for the given text.
+		if(aIdsFound->Find(contactId)==KErrNotFound)
+			{
+			TBool findTextInFields = ((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindFirstName)) ? (aStatement.ColumnTextL(firstNameIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) : EFalse;
+			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindLastName)) ? (aStatement.ColumnTextL(lastNameIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) : EFalse);
+			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindCompanyName)) ? (aStatement.ColumnTextL(companyNameIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) : EFalse);
+			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindFirstNamePronunciation)) ? (aStatement.ColumnTextL(firstNamePrnIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) :EFalse);
+			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindLastNamePronunciation)) ? (aStatement.ColumnTextL(lastNamePrnIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) :EFalse);
+			findTextInFields = findTextInFields || (((aFieldsToSearch & EFindInAllFields) || (aFieldsToSearch & EFindCompanyNamePronunciation)) ? (aStatement.ColumnTextL(companyNamePrnIndex).FindC(aText.Ptr(), aText.Length(), KCollationLevel) != KErrNotFound ) : EFalse);
+			
+			if(findTextInFields)
+				{
+				if (contactType == KUidContactICCEntry)
+					{
+					TInt error(iContactsFile.ContactProperties().ContactSynchroniserL(aSessionId).ValidateContact(MContactSynchroniser::ESearch,contactId));
+					User::LeaveIfError(error);
+					}
+				aIdsFound->AddL(contactId);
+				}
+			}
+		}
+	User::LeaveIfError(err);	
+
+	return (EFalse);
+	}
+
+/**
+Perform a find interation based on the given sql statement for the given text.
+
+@param aIdsFound On return the contact IDs found.
+@param aStatement sql statement
+
+@return ETrue if further iterations are required (i.e. view has not been fully
+evaluated and searched), EFalse otherwise.
+*/
+TBool CPlCollection::PerformIdFindIterationL(CContactIdArray *aIdsFound, RSqlStatement aStatement)
+	{
+	const TInt idIndex = aStatement.ColumnIndex(KContactId);
+	User::LeaveIfError(idIndex);	
+	TInt err;
+	while((err = aStatement.Next()) == KSqlAtRow)
+		{
+		TInt contactId = aStatement.ColumnInt(idIndex);
+		
+		// Check that the contact is not already present in the given contact
+		// IDs before adding it to the array of contact IDs.
+		if(aIdsFound->Find(contactId) == KErrNotFound)
+			{
+			aIdsFound->AddL(contactId);
+			}
+		}
+	User::LeaveIfError(err);	
+
+	return (EFalse);
+	}
+
+/**
+Utility method used to build the search string
+*/
+void AppendSearchStringSegment(TDes16& aOrderFields,const TDesC& aColName,  
+	const TPtrC aTxtPtr, TBool aAppendOr)
+	{
+	aOrderFields.Append(KLeftBracket);
+	aOrderFields.Append(aColName);
+	aOrderFields.Append(KLikeString);
+	aOrderFields.Append(aTxtPtr);
+	aOrderFields.Append(KLikeStringRight);
+	if(aAppendOr)
+		{
+		aOrderFields.Append(KOR);
+		}
+	}
+
+/**
+Utility method used to build search string
+*/
+void ConstructSearchString(TInt aFieldDef,TInt aNoFields,TDes16& aOrderFields,TPtrC aTxtPtr)
+	{
+	const void* KColNamesFields[] =
+		{
+		&KContactFirstName, &KContactLastName, &KContactCompanyName,
+		&KContactFirstNamePrn, &KContactLastNamePrn,
+		&KContactLastNamePrn
+		};
+		
+ 	for(TInt ii=0;ii<aNoFields;ii++)
+		{
+		for(TInt name = 0; name < sizeof(KNameFlags)/sizeof(TFindFieldFlags); ++name)
+			{
+			if(aFieldDef&KNameFlags[name])
+				{
+				AppendSearchStringSegment(aOrderFields,*((TDesC*)KColNamesFields[name]),  aTxtPtr, (ii+1)<aNoFields);
+				aFieldDef &= ~KNameFlags[name];
+				break;
+				}
+			}
+		}
+	}
+
+
+/**
+This method is required for asynchronous finds which have an initialisation
+method followed by one or more calls to the FindAsyncL() method.  The class
+needs to be reset to a known state when a find is completed.
+*/
+void CPlCollection::Reset()
+	{
+	if ( !iRSqlstatementsWorking )
+        {
+        //If RSqlstatements was reseted, don't reset it again.
+        return;
+        }
+	// Could introduce methods specific to the find operation such that this
+	// method is called only if an asynchronous find has taken place. 
+	delete iFieldDef;
+	iFieldDef = NULL;
+	delete iTextDef;
+	iTextDef = NULL;
+	delete iText;
+	iText = NULL;
+	delete iOriginalText;
+	iOriginalText = NULL;
+	delete iFindWords;
+	iFindWords = NULL;
+	delete iFindWords2;
+	iFindWords2 = NULL;
+	iNoIdentitySearchColumns = 0;
+	iFindFlags = 0;
+	iFindState = 0;	
+	
+	selectBlobStatement.Close();
+	selectIdentityStatement.Close();
+	selectEmailStatement.Close();
+	selectSIPStatement.Close();
+	selectIdFromIdentityStatement.Close();
+	iRSqlstatementsWorking = EFalse;
+	}
+
+
+/**
+Initialise the Persistence Layer collection class ready for iterative calls to
+the FindAsyncL() method.  This form of initialisation is for an asynchronous
+find which uses text and a field definition.
+
+@param aText Find text.
+@param aFieldDef Field definition to use in find.
+
+@leave KErrNoMemory Out of memory.
+*/
+void CPlCollection::FindAsyncInitL(const TDesC& aText,CContactItemFieldDef* aFieldDef)
+	{
+	_LIT(KWhereEmailSIPClause, "(%S = %d) AND (%S LIKE '%S')");
+	// Persistence Layer CPlCollection is not deleted but Reset()'s the member
+	// variables for iterative FindAsyncL() calls.
+	Reset();
+	iRSqlstatementsWorking = ETrue;
+	iText = CreateFindTextL(aText);
+	iFieldDef = aFieldDef;
+	iOriginalText = aText.AllocL();
+	ConstructBitwiseFindFlags(iFindFlags,iNoIdentitySearchColumns,iFieldDef);
+	// Construct RSqlStatements used for search
+	
+	HBufC *findText = CreateFindTextL(*iOriginalText);
+	CleanupStack::PushL(findText);
+	
+	// first construct select statement for searching in identity fields
+	if ( SearchIdentityFieldsRequired(iFindFlags) )
+		{
+		_LIT(KWhereClause,"(%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S') OR (%S LIKE '%S')");
+		HBufC* searchCond=HBufC::NewLC(KWhereClause().Length() +
+						KContactFirstName().Length() + findText->Length() +
+						KContactLastName().Length() + findText->Length() +
+						KContactCompanyName().Length() + findText->Length() +
+						KContactFirstNamePrn().Length() + findText->Length() +
+						KContactLastNamePrn().Length() + findText->Length() +
+						KContactCompanyNamePrn().Length() + findText->Length());
+		searchCond->Des().Format(KWhereClause, &KContactFirstName, findText,
+						&KContactLastName, findText, &KContactCompanyName, findText,
+						&KContactFirstNamePrn, findText, &KContactLastNamePrn, findText,
+						&KContactCompanyNamePrn, findText);
+					
+		iSelectStatement->Reset();	
+		iSelectStatement->SetParamL(KContactId, KSpace);
+		iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+		iSelectStatement->SetParamL(KContactFirstName, KSpace);
+		iSelectStatement->SetParamL(KContactLastName, KSpace);
+		iSelectStatement->SetParamL(KContactCompanyName, KSpace);
+		iSelectStatement->SetParamL(KContactFirstNamePrn, KSpace);
+		iSelectStatement->SetParamL(KContactLastNamePrn, KSpace);
+		iSelectStatement->SetParamL(KContactCompanyNamePrn, KSpace);
+		iSelectStatement->SetConditionL(*searchCond);
+		
+		User::LeaveIfError(selectIdentityStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+		CleanupStack::PopAndDestroy(searchCond); 
+		}
+	//end construction for statement for searching in identity fields
+
+	//construct statement for search email
+	if (iFindFlags & (EFindInAllFields | EFindInEmailField))
+		{
+		TCntSqlStatementType statementType(ESelect, KSqlContactCommAddrTableName);
+		CCntSqlStatement* cntSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
+		CleanupStack::PushL(cntSelectStatement);
+	
+		HBufC* searchCond = HBufC::NewLC(KWhereEmailSIPClause().Length()+ 
+				KCommAddrType().Length() + 
+				KCommAddrValue().Length() + findText->Length());
+		searchCond->Des().Format(KWhereEmailSIPClause, 
+				&KCommAddrType, CPplCommAddrTable::EEmailAddress, 
+				&KCommAddrValue, findText);
+	
+		cntSelectStatement->SetParamL(KContactId, KSpace);
+		cntSelectStatement->SetConditionL(*searchCond);
+
+		User::LeaveIfError(selectEmailStatement.Prepare(iContactsFile.NamedDatabase(), cntSelectStatement->SqlStringL()));
+		CleanupStack::PopAndDestroy(2, cntSelectStatement); // cntSelectStatement, searchCond
+		}
+	//end construction for statement for search email
+
+	//construct statement for search sip values
+	if (iFindFlags & (EFindInAllFields | EFindInSIPField))
+		{
+		TCntSqlStatementType statementType(ESelect, KSqlContactCommAddrTableName);
+		CCntSqlStatement* cntSelectStatement = TSqlProvider::GetSqlStatementL(statementType);
+		CleanupStack::PushL(cntSelectStatement);
+	
+		HBufC* searchCond = HBufC::NewLC(KWhereEmailSIPClause().Length()+ 
+				KCommAddrType().Length() + 
+				KCommAddrValue().Length() + findText->Length());
+		searchCond->Des().Format(KWhereEmailSIPClause, 
+				&KCommAddrType, CPplCommAddrTable::ESipAddress, 
+				&KCommAddrValue, findText);
+	
+		cntSelectStatement->SetParamL(KContactId, KSpace);
+		cntSelectStatement->SetConditionL(*searchCond);
+
+		User::LeaveIfError(selectSIPStatement.Prepare(iContactsFile.NamedDatabase(), cntSelectStatement->SqlStringL()));
+		CleanupStack::PopAndDestroy(2, cntSelectStatement); // cntSelectStatement, searchCond
+		}
+	//end construction for statement for search sip values
+
+	//construct statement for search in blob
+	if (iFindFlags & EFindInAllFields)
+		{
+		iSelectStatement->Reset();
+		iSelectStatement->SetParamL(KContactId, KSpace);
+		iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+		iSelectStatement->SetParamL(KContactTextFieldHeader, KSpace);
+		iSelectStatement->SetParamL(KContactTextFields, KSpace);
+		
+		User::LeaveIfError(selectBlobStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+		}
+	//end construction for statement for search in blob
+	
+	CleanupStack::PopAndDestroy(findText);
+	}
+
+
+/**
+Add the required fields and search text for SQL query.  Used for asynchronous
+find which uses a text definition.
+
+@see CPlCollection::FindAsyncTextDefInitL()
+	
+@param aOrderFields On return contains the required fields and search text for
+SQL query.
+*/
+void CPlCollection::doAppendFieldsToSearchString(HBufC* aOrderFields) const
+  	{
+  	TInt noOfFindWords = iFindWords2->Count();
+  	TPtr16 orderFieldPtr = aOrderFields->Des();
+  	for(TInt searchWord = 0;searchWord < noOfFindWords; ++searchWord)
+  		{
+  		ConstructSearchString(iFindFlags,iNoIdentitySearchColumns,orderFieldPtr,(*iFindWords2)[searchWord]);
+  		if ((searchWord+1) < noOfFindWords)
+  			{
+  			orderFieldPtr.Append(KOR);
+  			}
+  		}		
+  	}
+
+
+/**
+Initialise the Persistence Layer collection class ready for iterative calls to
+the FindAsyncL() method.  This form of initialisation is for an asynchronous
+find which uses a text definition and an array of "find words".
+
+@param aWords "Find words" array.
+@param aTextDef Text definition to use in find.
+*/
+void CPlCollection::FindAsyncTextDefInitL(const CDesCArray& aWords,CContactTextDef* aTextDef)
+	{
+	// Persistence Layer CPlCollection is not deleted but Reset()'s the member
+	// variables for iterative FindAsyncL() calls.
+	Reset();
+    iRSqlstatementsWorking = ETrue;
+	iFindWords = new(ELeave) CDesCArrayFlat(5);
+	iFindWords2 = new(ELeave) CDesCArrayFlat(5);
+	for(TInt loop = 0;loop < aWords.MdcaCount();++loop)
+		{
+		// Construct iFindWords2 which contains all the strings in the search
+		// surrounded by a %.
+		TPtrC findWord(aWords.MdcaPoint(loop));
+		TKeyCmpTextLength key;
+		HBufC* bufPtr = findWord.AllocLC();
+		iFindWords->CArrayFixBase::InsertIsqAllowDuplicatesL(&bufPtr,key);
+		CleanupStack::Pop(); // bufPtr
+		HBufC *findText = CreateFindTextL(findWord);
+		CleanupStack::PushL(findText);
+		iFindWords2->AppendL(*findText);
+		CleanupStack::PopAndDestroy(); // findText
+		}
+
+	iTextDef = aTextDef;
+	ConstructBitwiseFlagsFromTextDef(iFindFlags,iNoIdentitySearchColumns,iTextDef);
+
+	iSelectStatement->Reset();	
+	iSelectStatement->SetParamL(KContactId, KSpace);
+	iSelectStatement->SetParamL(KContactTypeFlags, KSpace);
+	iSelectStatement->SetParamL(KContactFirstName, KSpace);
+	iSelectStatement->SetParamL(KContactLastName, KSpace);
+	iSelectStatement->SetParamL(KContactCompanyName, KSpace);
+	iSelectStatement->SetParamL(KContactFirstNamePrn, KSpace);
+	iSelectStatement->SetParamL(KContactLastNamePrn, KSpace);
+	iSelectStatement->SetParamL(KContactCompanyNamePrn, KSpace);
+		
+	if(UsesIdentityFieldsOnly(iFindFlags))
+		{
+		TInt querySize = ApproximateSizeOfSearchString(); 
+		HBufC* searchCond = HBufC::NewLC(querySize); 
+		doAppendFieldsToSearchString(searchCond);
+		iSelectStatement->SetConditionL(*searchCond);
+		CleanupStack::PopAndDestroy(searchCond); 
+		}
+		
+	User::LeaveIfError(selectIdFromIdentityStatement.Prepare(iContactsFile.NamedDatabase(), iSelectStatement->SqlStringL()));
+	}
+
+
+/**
+This method does not do any searching.  It simply extracts the contact IDs from
+the view and (ultimately) returns them to the CIdleFinder object on the client
+side.
+
+The client can then call CIdleFinder::CheckFindL() to perform the actual search.
+Searching cannot be performed server-side because of the need to call a client
+supplied callback method (the "find words parser" callback).
+
+@param aIdArray Contact IDs extracted from the view.
+@param aSessionId Session ID (only relevant for ICC contacts).
+
+@return ETrue if further iterations are required (i.e. view has not been fully
+evaluated), EFalse otherwise.
+*/
+TBool CPlCollection::GetContactIdsForTextDefFindL(CContactIdArray* aIdArray, TUint aSessionId)
+	{
+	TInt iterCount = 0;
+	TInt err;
+	
+	const TInt idIndex = selectIdFromIdentityStatement.ColumnIndex(KContactId);
+	User::LeaveIfError(idIndex);
+	const TInt typeFlagsIndex = selectIdFromIdentityStatement.ColumnIndex(KContactTypeFlags);
+	User::LeaveIfError(typeFlagsIndex);
+	
+	while(iterCount<KFindIterations)
+		{
+		err = selectIdFromIdentityStatement.Next();
+		if(err != KSqlAtRow)
+			{
+			User::LeaveIfError(err);
+			break;
+			}
+			
+		TInt typeFlags = selectIdFromIdentityStatement.ColumnInt(typeFlagsIndex);
+		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
+		TContactItemId contactId = selectIdFromIdentityStatement.ColumnInt(idIndex);
+		
+		if (contactType == KUidContactICCEntry)
+			{
+			User::LeaveIfError(iContactsFile.ContactProperties().ContactSynchroniserL(aSessionId).ValidateContact(MContactSynchroniser::ESearch,contactId));
+			User::LeaveIfError(iContactsFile.ContactProperties().ContactSynchroniserL(aSessionId).ValidateContact(MContactSynchroniser::ERead,contactId));
+			}
+		// Check that the contact is not already present in the given
+		// contact IDs before adding to array.
+		if(aIdArray->Find(contactId) == KErrNotFound)
+			{
+			aIdArray->AddL(contactId);		
+			}
+		}
+	
+	return(iterCount == KFindIterations);	
+	}
+
+
+/**
+Perform an asynchronous find iteration.
+
+@param aMoreToGo On return ETrue if further iterations are required to complete
+the asynchronous find, EFalse otherwise.
+@param aSessionId Session ID (only relevant for ICC contacts).
+
+@return Array of contact ID found in this find iteration.
+*/
+CContactIdArray* CPlCollection::FindAsyncL(TBool& aMoreToGo, TUint aSessionId)
+	{
+	CContactIdArray* idArray = CContactIdArray::NewLC();
+	TBool moreToGo = EFalse;
+
+	if (iFindWords) // Text definition and "find words".
+		{
+		TRAPD(err, moreToGo=GetContactIdsForTextDefFindL(idArray, aSessionId));
+
+		if (err != KErrNone)
+			{
+			moreToGo = EFalse;
+			Reset();
+			User::Leave(err);			
+			}
+
+		if(moreToGo == EFalse)
+			{
+			iFindState |= EFindInTextDefFinished;
+			}
+		}
+	else // Search for a single string.
+		{
+		if(!(iFindState & EFindInBlobFinished) && (iFindFlags & EFindInAllFields))
+			{
+			// Search in searchable text (contents of BLOB).
+			if(!FindL(idArray, *iText, iFieldDef, selectBlobStatement, aSessionId))
+				{
+				iFindState |= EFindInBlobFinished;
+				}
+			else
+			    {
+        		moreToGo = ETrue;
+			    }	
+			}
+
+		if(!(iFindState & EFindInIdentityFinished))
+			{
+			if(SearchIdentityFieldsRequired(iFindFlags))
+				{		
+				// Search in identity fields.
+				if(!PerformFindIterationL(idArray, *iOriginalText, selectIdentityStatement, iFindFlags, aSessionId))
+					{
+					iFindState |= EFindInIdentityFinished;
+					}
+    			else
+    			    {
+            		moreToGo = ETrue;
+    			    }	
+				}
+			}
+
+		if(!(iFindState & EFindInEmailFinished))
+			{
+			if(iFindFlags & (EFindInAllFields | EFindInEmailField))
+				{
+				// Search in email fields.		
+				if(!PerformIdFindIterationL(idArray, selectEmailStatement))
+					{
+					iFindState |= EFindInEmailFinished;
+					}
+    			else
+    			    {
+            		moreToGo = ETrue;
+    			    }	
+				}
+			}
+		
+		if(!(iFindState & EFindInSIPFinished))
+			{
+			if(iFindFlags & (EFindInAllFields | EFindInSIPField))
+				{
+				// Search in email fields.		
+				if(!PerformIdFindIterationL(idArray, selectSIPStatement))
+					{
+					iFindState |= EFindInSIPFinished;
+					}
+    			else
+    			    {
+            		moreToGo = ETrue;
+    			    }	
+				}
+			}
+		}
+
+
+    if(!moreToGo)
+        {
+		Reset();
+        }
+
+/*        
+	// Check if we have finished searching.
+	if ((iFindState&(EFindInBlobFinished|EFindInIdentityFinished|EFindInEmailFinished)) == (EFindInBlobFinished|EFindInIdentityFinished|EFindInEmailFinished)
+		 || iFindState&EFindInTextDefFinished)
+		{
+		moreToGo = EFalse;
+		Reset();
+		}
+*/
+	aMoreToGo = moreToGo;
+
+	// Pop this off the cleanup stack, as we are passing on ownership to the calling method
+	CleanupStack::Pop(idArray);
+
+	return idArray;
+	}
+
+
+/**
+Perform a synchronous find for the given text and field definition.
+
+@param aIdsFound Contacts IDs found.
+@param aText Text to search for.
+@param aFieldDef Field definition to use.
+@param aSessionId Session ID (only relevant for ICC contacts).
+
+@return ETrue if all iterations have been completed, EFalse otherwise.
+*/
+TBool CPlCollection::FindL(CContactIdArray *aIdsFound, const TDesC& aText,const CContactItemFieldDef *aFieldDef, RSqlStatement aStatement, TUint aSessionId)
+	{
+  	const CContactTemplate& systemTemplate = iContactsFile.ContactProperties().SystemTemplateManager().TemplateL();
+
+	CContactItemField* field = CContactItemField::NewLC();	// construct just once
+
+	TInt endOfQueryString = aText.Length()-2;
+	TPtrC originalFindText = aText.Mid(1,endOfQueryString);
+
+	TInt iterCount = 0;
+	TInt err;
+	
+	const TInt idIndex = aStatement.ColumnIndex(KContactId);
+	User::LeaveIfError(idIndex);
+	const TInt typeFlagsIndex = aStatement.ColumnIndex(KContactTypeFlags);
+	User::LeaveIfError(typeFlagsIndex);
+	const TInt textHeaderIndex = aStatement.ColumnIndex(KContactTextFieldHeader);
+	User::LeaveIfError(textHeaderIndex);
+	const TInt textFieldsIndex = aStatement.ColumnIndex(KContactTextFields);
+	User::LeaveIfError(textFieldsIndex);
+	
+	while(iterCount<KFindIterations)
+		{
+		err = aStatement.Next();
+		if(err != KSqlAtRow)
+			{
+			User::LeaveIfError(err);
+			break;
+			}
+			
+		TInt typeFlags = aStatement.ColumnInt(typeFlagsIndex);
+		TUid contactType = TCntPersistenceUtility::TypeFlagsToContactTypeUid(typeFlags);
+
+		if (iContactsFile.ContactProperties().CheckType(contactType) )
+			{
+			TPtrC8 textHeader;
+			aStatement.ColumnBinary(textHeaderIndex, textHeader);
+			RDesReadStream textHeaderStream(textHeader);
+			CleanupClosePushL(textHeaderStream);
+
+			CEmbeddedStore* store = CEmbeddedStore::FromLC(textHeaderStream);
+			
+			TPtrC textFieldPtrC = aStatement.ColumnTextL(textFieldsIndex);
+			HBufC *textBuf = HBufC::NewLC(textFieldPtrC.Size());
+			textBuf->Des().Copy(textFieldPtrC);
+			
+			RStoreReadStream rootStream;
+			rootStream.OpenLC(*store ,store->Root());
+			
+			TCardinality  count;
+			rootStream >> count;
+
+			for (TInt i = 0;i < count; ++i)
+				{
+				field->Reset();
+				if (field->RestoreIfMatchL(rootStream,aFieldDef,&systemTemplate.CardFields(),textBuf,i))
+					{
+					if (field->StorageType() == KStorageTypeText && 
+						field->TextStorage()->Text().FindC(originalFindText.Ptr(), 
+						originalFindText.Length(), KCollationLevel) != KErrNotFound)
+						{
+						TContactItemId id = aStatement.ColumnInt(idIndex);
+						if(aIdsFound->Find(id) == KErrNotFound)
+							{
+							if (contactType == KUidContactICCEntry)
+								{
+								TInt error(iContactsFile.ContactProperties().ContactSynchroniserL(aSessionId).ValidateContact(MContactSynchroniser::ESearch,id));
+								User::LeaveIfError(error);
+								}
+							aIdsFound->AddL(id);
+							}
+						break;
+						}
+					}
+				}
+			CleanupStack::PopAndDestroy(4, &textHeaderStream); // rootStream, textBuf, textHeader, textHeaderStream
+			}
+		++iterCount;
+		}
+
+	CleanupStack::PopAndDestroy(field); 
+
+	return(iterCount == KFindIterations);
+	}
+
+/**
+Return an over-estimated string size for the amount of syntax required per field
+per search string for the Identity table.
+
+@return Maximum string size required for Identity table search syntax.
+*/
+TInt CPlCollection::MaximumSizeOfIdentitySearchSyntax()
+	{
+	TInt sqlLitSize;
+
+	sqlLitSize = KLeftBracket().Length() + KLikeString().Length() +
+		KLikeStringRight().Length() + KOR().Length();
+
+	sqlLitSize *= iNoIdentitySearchColumns;
+
+	sqlLitSize += KContactFirstName().Length() + KContactLastName().Length() +
+		KContactCompanyName().Length();
+
+	sqlLitSize += KContactFirstNamePrn().Length() +
+		KContactLastNamePrn().Length() +
+		KContactCompanyNamePrn().Length();
+
+	return(sqlLitSize);
+	}
+	
+/**
+Determine the approximate size of the string required to construct the SQL query
+on the Identity table when using the "find words".
+
+@return Approximate size of search string.
+*/
+TInt CPlCollection::ApproximateSizeOfSearchString()
+	{
+	TInt sqlLitSize = MaximumSizeOfIdentitySearchSyntax();
+
+	TInt noOfFindWords=iFindWords2->Count();
+	TInt size=0;
+
+	for(TInt searchWord=0;searchWord < noOfFindWords; ++searchWord)
+		{
+		size += (*iFindWords2)[searchWord].Length();
+		}
+	
+	TInt totalSize = noOfFindWords*sqlLitSize + iNoIdentitySearchColumns*size + 256;
+	
+	return totalSize;
+	}
+	
+/**
+Utility method used to filter hint fields
+*/	
+TBool CPlCollection::HintFieldMatchesFilter(TInt aHintField, TInt aFilter)
+	{
+	TBool match=EFalse;
+
+	if (aFilter==CContactDatabase::EUnfiltered)
+		{
+		return ETrue;
+		}
+
+	if (aFilter & ~aHintField & (CContactDatabase::EWork | CContactDatabase::EHome))
+		{
+		return EFalse;
+		}
+
+	match = aFilter & aHintField
+		& (
+			  CContactDatabase::ELandLine
+			| CContactDatabase::ESmsable
+			| CContactDatabase::EMailable
+			| CContactDatabase::EFaxable
+			| CContactDatabase::EPhonable
+			| CContactDatabase::ERingTone
+			| CContactDatabase::EVoiceDial
+			| CContactDatabase::EIMAddress
+			| CContactDatabase::EWirelessVillage
+			| CContactDatabase::ECustomFilter1
+			| CContactDatabase::ECustomFilter2
+			| CContactDatabase::ECustomFilter3
+			| CContactDatabase::ECustomFilter4
+			);
+
+	return match;
+	}