metadataengine/server/src/mdssqlfindoperation.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 31 Mar 2010 22:19:07 +0300
branchRCL_3
changeset 17 50de4d668bb6
parent 15 3cebc1a84278
child 40 910a23996aa0
permissions -rw-r--r--
Revision: 201011 Kit: 201013

/*
* Copyright (c) 2005-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:  Manages object search from database using SQL,*
*/

#include "mdssqlfindoperation.h"

#include "mdcresult.h"
#include "mdcitem.h"
#include "mdcserializationbuffer.h"
#include "mdsfindsequence.h"
#include "mdsobjectdef.h"
#include "mdsnamespacedef.h"
#include "mdspropertydef.h"
#include "mdsfindsqlclause.h"
#include "mdsserver.h"
#include "mdsdbconnectionpool.h"
#include "mdeinternalerror.h"

const TInt KMaxResultSize = 1024*256; // 256 KiB

CMdSSqlFindOperation* CMdSSqlFindOperation::NewL(
    CMdSFindSequence& aFind,
    TUint aSetSize
    )
    {
    CMdSSqlFindOperation* that = CMdSSqlFindOperation::NewLC(
        aFind, aSetSize );
    CleanupStack::Pop( that );
    return that;
    }

CMdSSqlFindOperation* CMdSSqlFindOperation::NewLC(    
    CMdSFindSequence& aFind,
    TUint aSetSize
    )
    {
    CMdSSqlFindOperation* that = new (ELeave) CMdSSqlFindOperation(        
        aFind, 
        aSetSize
        );
    CleanupStack::PushL( that );
    that->ConstructL();
    return that;
    }

CMdSSqlFindOperation::CMdSSqlFindOperation(    
    CMdSFindSequence& aFind,
    TUint aSetSize
    )
    : iResultMode( EQueryResultModeFirst ), iResultRow(NULL),
    iResultRows(), iResultCount( 0 ), iResults( NULL ), iFind ( aFind ),
    iState( EStateIdle ), iSetSize( aSetSize ), iLimit( 0 ), 
    iLimitCounter( 0 ), iMemoryLimit( 0 ), 
    iHarvestingPrioritizationCount( 0 )
    {
    }

void CMdSSqlFindOperation::ConstructL()
    {    
	iFindClause = CMdSFindSqlClause::NewL( const_cast<CMdsSchema&>(iFind.Schema()) );	
    }


CMdSSqlFindOperation::~CMdSSqlFindOperation()
    {
	ConsumeRows();
    iResultRows.Close();

    iResultIds.Close();

    // doesn't own result row
    iResultRow = NULL;

    iQueryId.Close();

   	delete iResults;
   	delete iFindClause;
    }

TInt CMdSSqlFindOperation::ExecuteL()
    {
    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

    iResultRow = &iFindClause->ResultRow();
    iQueryType = iFindClause->QueryType();
    iResultMode = iFindClause->ResultMode();

	if( EQueryResultModeFirst >= iResultMode || EQueryResultModeLast <= iResultMode )
		{
#ifdef _DEBUG
		User::Panic( _L("MdSFOExe") , KErrMdEUnknownQueryResultMode );
#endif

		User::Leave( KErrMdEUnknownQueryResultMode );
		}

   	iFind.SetResultMode( iQueryType == EQueryTypeObject && iResultMode == EQueryResultModeItem );
        
   	connection.ExecuteQueryL( iFindClause->AsTextL(), iQueryId, iFindClause->Variables() );

    iState = EStateRunning;

	iSetCounter = 0;
	iMemoryLimit = 0;
	iHarvestingPrioritizationCount = 0;

    return FetchResultsL();
    }

TInt CMdSSqlFindOperation::ContinueL()
    {
    // Continue query: fetch next row
    iSetCounter = 0;
    iState = EStateRunning;

    return FetchResultsL();
    }

TInt CMdSSqlFindOperation::FetchResultsL()
    {
	iMemoryLimit += EstimateBaseResultSize();
	
	if( !iResultRow )
		{
#ifdef _DEBUG
		User::Panic( _L("MdSFOFe1") , KErrCorrupt );
#endif

		User::Leave( KErrCorrupt );
		}

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

    while( ETrue )
        {
        RRowData* resultRow = new (ELeave) RRowData();        
        CleanupStack::PushL( resultRow );
        CleanupClosePushL( *resultRow );

        resultRow->AppendColumnTypesL( *iResultRow );

        // fetch next DB row
        if ( !connection.NextRowL( iQueryId, *resultRow ) )
            {
            CleanupStack::PopAndDestroy( 2, resultRow ); // close and delete resultRow separately
            resultRow = NULL;

           	TRAPD( err, AddToContainerL() );

           	if( KErrNone != err )
           		{
           		iResults = NULL;
           		ConsumeRows();
           		}

           	connection.Terminate( iQueryId );
            iState = EStateDead;
            return KErrNone;
            }

        iMemoryLimit += EstimateResultRowSizeL( *resultRow );

		// Check if maximum memory limit is reached or 
		// set/limit counter is more than maximum set/limit size. 
		if( KMaxResultSize <= iMemoryLimit )
			{
			// Store all previus items to result buffer.

           	TRAPD( err, AddToContainerL() );

           	if( KErrNone != err )
           		{
           		iResults = NULL;
           		ConsumeRows();
           		}

			// add estimated size to next result set
	        iMemoryLimit = EstimateResultRowSizeL( *resultRow );

			if( EQueryResultModeItem == iResultMode || EQueryResultModeDistinctValues == iResultMode )
				{
				// add result row to result rows pointer array
	           	iResultRows.AppendL( resultRow );
				
				iSetCounter++;
	           	
				// pop result row from cleanup stack twice
				CleanupStack::Pop( 2, resultRow );
				}
			else
				{
				if( EQueryResultModeId == iResultMode )
					{					
					TItemId itemId = 0;
					resultRow->Column( 0 ).Get( itemId );
					iResultIds.AppendL( itemId );

					iSetCounter++;
					}
				else
					{
					TUint32 count;
					resultRow->Column( 0 ).Get( count );
					iResultCount += count;
					}

				// pop and destroy result row from cleanup stack twice
				CleanupStack::PopAndDestroy( 2, resultRow );
				}


			resultRow = NULL;

           	++iLimitCounter;
                
            iState = EStateIdle;
            connection.EnableTransaction( EFalse, iQueryId );
            return KFindSetReady;
			}
		else
			{
			if( EQueryResultModeItem == iResultMode || EQueryResultModeDistinctValues == iResultMode )
				{
				// add result row to result rows pointer array
	           	iResultRows.AppendL( resultRow );

				iSetCounter++;

				// pop result row from cleanup stack twice
				CleanupStack::Pop( 2, resultRow );
				}
			else 
				{
				if( EQueryResultModeId == iResultMode )
					{					
					TItemId itemId = 0;
					resultRow->Column( 0 ).Get( itemId );
					iResultIds.AppendL( itemId ); 

					iSetCounter++;
					}
				else
					{
					TUint32 count;
					resultRow->Column( 0 ).Get( count );
					iResultCount += count;
					}

				// pop and destroy result row from cleanup stack twice
				CleanupStack::PopAndDestroy( 2, resultRow );
				}

			resultRow = NULL;

			++iLimitCounter;
			}

        // check for different exit conditions
        if ( iState == EStateRunning )
            {
            if ( iLimitCounter >= iLimit )
                {
	           	TRAPD( err, AddToContainerL() );

	           	if( KErrNone != err )
	           		{
	           		iResults = NULL;
	           		ConsumeRows();
	           		}

	           	connection.Terminate( iQueryId );
                iState = EStateDead;
                return KErrNone;
                }
            else if( iSetCounter >= iSetSize )
                {
	           	TRAPD( err, AddToContainerL() );

	           	if( KErrNone != err )
	           		{
	           		iResults = NULL;
	           		ConsumeRows();
	           		}

                iState = EStateIdle;
                connection.EnableTransaction( EFalse, iQueryId );
                return KFindSetReady;
                }
            }
        else if ( iState == EStateStop )
            {
            // stop instructed
            connection.Terminate( iQueryId );
            iState = EStateDead;
            return KErrCancel;
            }
        else 
            {
#ifdef _DEBUG
	    	User::Panic( _L("MdSFOFe2") , KErrCorrupt );
#endif
	    	User::Leave( KErrCorrupt );
            }
        }
    }

TInt CMdSSqlFindOperation::EstimateBaseResultSize()
	{
	switch( iResultMode )
		{
		case EQueryResultModeItem:
			return sizeof(TMdCItems);

		case EQueryResultModeId:
			return sizeof(TMdCItemIds);

		case EQueryResultModeCount:
			return sizeof(TMdCItemCounts);

		case EQueryResultModeDistinctValues:
			return sizeof(TMdCItemIds);

		// should never happen
		default:
#ifdef _DEBUG
			User::Panic( _L( "MdSFOEBS" ), KErrMdEUnknownQueryResultMode );
#endif
			return 0;
		}
	}

TInt CMdSSqlFindOperation::EstimateResultRowSizeL( RRowData& aRow )
	{
	if( iResultMode == EQueryResultModeId )
		{
		return CMdCSerializationBuffer::KRequiredSizeForTItemId;
		}
	else if( iResultMode == EQueryResultModeCount )
		{
		return 0;
		}
	else if( iResultMode == EQueryResultModeDistinctValues )
		{
		if( iFindClause->PropertyFilters().Count() != 1 )
			{
			User::Leave( KErrCorrupt );
			}

		const RPointerArray<CMdsPropertyDef>& propertyFilters = iFindClause->PropertyFilters();

		TInt rowSize = 0;
		if( propertyFilters[0]->GetType() == EPropertyText )
	    	{
	    	if ( !aRow.Column( 0 ).IsNull() )
	    		{
				// Required size for text property
				TPtrC16 value = TPtr16((TUint16*)0, 0);
				aRow.Column( 0 ).Get( value );
				rowSize += CMdCSerializationBuffer::RequiredSize( value );
	    		}	    		
	    	}
	    else
	    	{
#ifdef _DEBUG
	    	User::Panic( _L("MdSFOEs1") , KErrMdEUnknownPropertyType );
#endif
	    	User::Leave( KErrMdEUnknownPropertyType );
	    	}
	    	
	    return rowSize;
		}

	switch( iQueryType )
		{
		case EQueryTypeObject:
			{
			TInt rowSize = sizeof(TMdCObject);

			const TInt KUriColumn = 7;

			TPtrC16 uri = TPtr16((TUint16*)0, 0);
			
			// Required size for object URI
			if (!aRow.Column( KUriColumn ).IsNull())
				{
				aRow.Column( KUriColumn ).Get( uri );
				rowSize += CMdCSerializationBuffer::RequiredSize( uri );
				}

			if( iFindClause->NoObjectLocking() && iFindClause->ObjectDef() && iFindClause->ObjectDef()->GetId() != KBaseObjectDefId )
				{
				// check if object is placeholder and add it to count of harvester 
				// prioritization URIs
				const TInt KFlagsColumn = 2;
				TUint32 flags = 0;
				aRow.Column( KFlagsColumn ).Get( flags );
				if( flags & EMdEObjectFlagPlaceholder )
					{
					if( iFind.Server().ReserveSpaceHarvestingPrioritizationUri( uri ) )
						{
						iHarvestingPrioritizationCount++;
						}
					}
				}

			// Required size for properties
			CMdsObjectDef* objectDef = iFindClause->ObjectDef();

			if( !objectDef )
				{
#ifdef _DEBUG
				User::Panic( _L("MdSFOEs2") , KErrMdEUnknownObjectDef );
#endif
				User::Leave( KErrMdEUnknownObjectDef );
				}

			const RPointerArray<CMdsPropertyDef>& propertyFilters = iFindClause->PropertyFilters();

			// no property filterss
			if( propertyFilters.Count() <= 0 )
				{
				const TInt count = objectDef->GetAllPropertiesCount();

				// space for every property, even if it's "null"
				rowSize += count * sizeof(TMdCProperty);

				for( TInt i = 0; i < count; i++ )
					{
					const CMdsObjectDef::TMdsColumnOrder& propertyColumn = 
						objectDef->GetPropertyColumnL( i );

					TColumn& column = aRow.Column( propertyColumn.iColumnId );

					if( column.IsNull() )
						{
						continue;
						}

					if( propertyColumn.iPropertyDef.GetType() == EPropertyText )
				    	{
						// Required size for text in text property
						TPtrC16 value = TPtr16((TUint16*)0, 0);
						column.Get( value );
						rowSize += CMdCSerializationBuffer::RequiredSize( value );
				    	}
					}
				}
			// property filters
			else
				{
				const TInt count = propertyFilters.Count();

				// space for every property, even if it's "null"
				rowSize += count * sizeof(TMdCProperty);

				for( TInt i = 0; i < count; i++ )
					{
					CMdsPropertyDef* propDef = propertyFilters[i];

					if( !propDef )
						{
#ifdef _DEBUG
						User::Panic( _L("MdSFOEs3") , KErrMdEUnknownPropertyDef );
#endif						
						User::Leave( KErrMdEUnknownPropertyDef );
						}

					TColumn& column = aRow.Column( KBaseObjectBasicValueColumnOffset + i );

					if( column.IsNull() )
						{
						continue;
						}

					if( propDef->GetType() == EPropertyText )
				    	{
						// Required size for text in text property
						TPtrC16 value = TPtr16((TUint16*)0, 0);
						column.Get( value );
						rowSize += CMdCSerializationBuffer::RequiredSize( value );
				    	}
					}
				}

			if( FindCriteria().IncludesFreetexts() )
				{
				// In result row the second lastest column is free text count
				const TInt freeTextCountColumn = aRow.Size() - 2;

				// Get free text count
				TUint32 freeTextCount = 0;
				aRow.Column( freeTextCountColumn ).Get( freeTextCount );

				if( freeTextCount > 0 )
					{
					// In result row last column is total free text length
					const TInt totalFreeTextsLengthColumn = aRow.Size() - 1;

					// Get total free text length.
					TUint32 totalFreeTextsLength = 0;
					aRow.Column( totalFreeTextsLengthColumn ).Get( totalFreeTextsLength );

					// Required size for free texts.
					// For every free text length (TUint16) 
					rowSize += freeTextCount * ( CMdCSerializationBuffer::KRequiredSizeForEmptyText );
					// and total free text length * TUint16
					rowSize += totalFreeTextsLength * sizeof( TUint16 );
					}
				}

			return rowSize;
			}

		case EQueryTypeRelation:
			return sizeof(TMdCRelation);

		case EQueryTypeEvent:
			{
			TInt rowSize = sizeof(TMdCEvent);

			// Required size for source and participant texts
			TPtrC16 source = TPtr16((TUint16*)0, 0);
			aRow.Column( 4 ).Get( source );
			rowSize += CMdCSerializationBuffer::RequiredSize( source );

			TPtrC16 participant = TPtr16((TUint16*)0, 0);
			aRow.Column( 5 ).Get( participant );
			rowSize += CMdCSerializationBuffer::RequiredSize( participant );

			return rowSize;
			}

		default:
#ifdef _DEBUG
			User::Panic( _L( "MdSFOEs4" ), KErrMdEUnknownQueryResultMode );
#endif
			return 0;
		}
	}

TInt CMdSSqlFindOperation::State()
    {
    return iState;
    }

void CMdSSqlFindOperation::Cancel()
    {
    if ( iState == EStateRunning )
        {
        iState = EStateStop;
        }
    }

RPointerArray<HBufC>& CMdSSqlFindOperation::QueryFreeText()
	{
	return iFindClause->QueryFreeText();
	}


CMdSFindSqlClause& CMdSSqlFindOperation::FindCriteria()
    {
    return *iFindClause;
    }

CMdCSerializationBuffer* CMdSSqlFindOperation::Results()
	{
	CMdCSerializationBuffer* results = iResults;
	iResults = NULL;
	return results;
	}

void CMdSSqlFindOperation::SetLimit(TUint32 aLimit)
	{
	iLimit = aLimit;
	}

void CMdSSqlFindOperation::SetOffset(TUint32 aOffset)
	{
	iOffset = aOffset;
	}

TMdCOffset CMdSSqlFindOperation::AddItemToContainerL( RRowData &aRow, TMdCOffset aFreespaceOffset )
    {
    switch( iQueryType )  
        {
        case EQueryTypeObject:
            {
            aFreespaceOffset = AddObjectToContainerL( aRow, aFreespaceOffset );
            break;
            }
        case EQueryTypeEvent:
            {
            TMdCEvent event;
            TPtrC16 source = TPtr16( ( TUint16* )0, 0 );      //KNullPtr16;
            TPtrC16 participant = TPtr16( ( TUint16* )0, 0 ); //KNullPtr16;

            aRow.Column( 0 ).Get( event.iId );
            aRow.Column( 1 ).Get( event.iObjectId );
            aRow.Column( 2 ).Get( event.iDefId );
            aRow.Column( 3 ).Get( event.iTime );
            aRow.Column( 4 ).Get( source );
            aRow.Column( 5 ).Get( participant );

            const TMdCOffset eventOffset = iResults->Position();
            
            if ( source.Length() > 0 )
            	{
            	event.iSourceText.iPtr.iCount = source.Length();
            	event.iSourceText.iPtr.iOffset = aFreespaceOffset;
            	iResults->PositionL( aFreespaceOffset );
            	aFreespaceOffset = iResults->InsertL( source );
            	}
            else
            	{
            	event.iSourceText.iPtr.iCount = 0;
            	event.iSourceText.iPtr.iOffset = KNoOffset;
            	}

            if ( participant.Length() > 0 )
            	{
            	event.iParticipantText.iPtr.iCount = participant.Length();
            	event.iParticipantText.iPtr.iOffset = aFreespaceOffset;
            	iResults->PositionL( aFreespaceOffset );
                aFreespaceOffset = iResults->InsertL( participant );
            	}
            else
            	{
            	event.iParticipantText.iPtr.iCount = 0;
            	event.iParticipantText.iPtr.iOffset = KNoOffset;
            	}
            
            iResults->PositionL( eventOffset );
            event.SerializeL( *iResults );
            break;
            }
        case EQueryTypeRelation:
            {
            TMdCRelation relation;
            TUint32 flags           ( 0 );

            aRow.Column( 0 ).Get( relation.iId );
            aRow.Column( 1 ).Get( flags );
            aRow.Column( 2 ).Get( relation.iDefId );
            aRow.Column( 3 ).Get( relation.iLeftObjectId );
            aRow.Column( 4 ).Get( relation.iRightObjectId );
            aRow.Column( 5 ).Get( relation.iParameter );
            aRow.Column( 6 ).Get( relation.iGuidHigh );
            aRow.Column( 7 ).Get( relation.iGuidLow );
            aRow.Column( 8 ).Get( relation.iLastModifiedDate );

            relation.SerializeL( *iResults );
            break;
            }
        // Unknown query type
        default:
            {
#ifdef _DEBUG
			User::Panic( _L("MdSFOAd1") , KErrMdEUnknownQueryType );
#endif
            User::Leave( KErrMdEUnknownQueryType );
            }
        }
    return aFreespaceOffset;
    }

void CMdSSqlFindOperation::AddIdToContainerL( TItemId aId )
    {
    switch( iQueryType )  
        {
        case EQueryTypeObject:
        case EQueryTypeEvent:
        case EQueryTypeRelation:
            {
            iResults->InsertL( aId );
            break;
            }
        default:
            {
#ifdef _DEBUG
			User::Panic( _L("MdSFOAd2") , KErrMdEUnknownQueryType );
#endif
            User::Leave( KErrMdEUnknownQueryType );
            }
        }
    }

void CMdSSqlFindOperation::CreateItemL()
    {
    TMdCItems items;
    items.iNamespaceDefId = iFindClause->NamespaceDef()->GetId();
    items.iObjects.iPtr.iCount = 0;
    items.iObjects.iPtr.iOffset = KNoOffset;
    items.iRelations.iPtr.iCount = 0;
    items.iRelations.iPtr.iOffset = KNoOffset;
    items.iEvents.iPtr.iCount = 0;
    items.iEvents.iPtr.iOffset = KNoOffset;

    // move after main header
    iResults->PositionL( sizeof(TMdCItems) );

    TUint32 count = iResultRows.Count();
    TMdCOffset freetextOffset = KNoOffset;
    switch( iQueryType )
        {
        case EQueryTypeObject:
            {
            // add objects header
            items.iObjects.iPtr.iCount = count;
            items.iObjects.iPtr.iOffset = iResults->Position();
            freetextOffset = items.iObjects.iPtr.iOffset + count * sizeof(TMdCObject);
            
            // initializate server's harvesting prioritization buffer
        	if( iHarvestingPrioritizationCount > 0 )
        		{
        		iFind.Server().StartAddingHarvestingPrioritizationUrisL();
        		}		

            break;
            }
        case EQueryTypeEvent:
            {
            // add objects header
            items.iEvents.iPtr.iCount = count;
            items.iEvents.iPtr.iOffset = iResults->Position();
            freetextOffset = items.iEvents.iPtr.iOffset + count * sizeof(TMdCEvent);
            break;
            }
        case EQueryTypeRelation:
            {
            // add objects header
            items.iRelations.iPtr.iCount = count;
            items.iRelations.iPtr.iOffset = iResults->Position();
            freetextOffset = items.iRelations.iPtr.iOffset + count * sizeof(TMdCRelation);
            break;
            }
        default:
            {
#ifdef _DEBUG
			User::Panic( _L("MdSFOCr1") , KErrMdEUnknownQueryType );
#endif
			User::Leave( KErrMdEUnknownQueryType );
            }
        }

  	iResults->PositionL( KNoOffset );
	items.SerializeL( *iResults );

    //Set offset to objects/events/relations
    for( TInt i = 0; i < count; i++ )
        {
        switch ( iQueryType )
        	{
			case EQueryTypeObject:
	        	{
	            iResults->PositionL( items.iObjects.iPtr.iOffset
	            		+ i * sizeof(TMdCObject) );
	            freetextOffset = AddItemToContainerL( *iResultRows[i], freetextOffset );
	            break;
	            }
	        case EQueryTypeEvent:
	        	{
	            iResults->PositionL( items.iEvents.iPtr.iOffset
	            		+ i * sizeof(TMdCEvent) );
	            freetextOffset = AddItemToContainerL( *iResultRows[i], freetextOffset );
	            break;
	            }
	        case EQueryTypeRelation:
	        	{
	            iResults->PositionL( items.iRelations.iPtr.iOffset
	            		+ i * sizeof(TMdCRelation) );
	            freetextOffset = AddItemToContainerL( *iResultRows[i], freetextOffset );
			    break;
	            }
	        default:
	        	{
#ifdef _DEBUG
	        	User::Panic( _L("MdSFOCr2") , KErrMdEUnknownQueryType );
#endif
	        	User::Leave( KErrMdEUnknownQueryType );
	        	}
        	}
        }
    }

void CMdSSqlFindOperation::CreateCountL()
    {
    TMdCItemCounts itemCounts;
    itemCounts.iNamespaceDefId = iFindClause->NamespaceDef()->GetId();
    itemCounts.iObjects = 0;
    itemCounts.iEvents = 0;
    itemCounts.iRelations = 0;

    switch( iQueryType )
        {
        case EQueryTypeObject:
            {
            itemCounts.iObjects = iResultCount;
            break;
            }
        case EQueryTypeEvent:
            {
            itemCounts.iEvents = iResultCount;
            break;
            }
        case EQueryTypeRelation:
            {
            itemCounts.iRelations = iResultCount;
            break;
            }
        default:
            {
#ifdef _DEBUG
			User::Panic( _L("MdSFOCr3") , KErrMdEUnknownQueryType );
#endif
			User::Leave( KErrMdEUnknownQueryType );
            }
        }

    itemCounts.SerializeL( *iResults );
    }

void CMdSSqlFindOperation::CreateIdL()
    {
    TMdCItemIds itemIds;
    itemIds.iNamespaceDefId = iFindClause->NamespaceDef()->GetId();
    itemIds.iErrorCode = KErrNone;
    itemIds.iObjectIds.iPtr.iCount = 0;
    itemIds.iObjectIds.iPtr.iOffset = KNoOffset;
    itemIds.iObjectUris.iPtr.iCount = 0;
    itemIds.iObjectUris.iPtr.iOffset = KNoOffset;
    itemIds.iEventIds.iPtr.iCount = 0;
    itemIds.iEventIds.iPtr.iOffset = KNoOffset;
    itemIds.iRelationIds.iPtr.iCount = 0;
    itemIds.iRelationIds.iPtr.iOffset = KNoOffset;

    iResults->PositionL( sizeof(TMdCItemIds) );

    TUint32 count = iResultIds.Count();
    switch( iQueryType )  
        {
        case EQueryTypeObject:
            {
            itemIds.iObjectIds.iPtr.iCount = count;
            itemIds.iObjectIds.iPtr.iOffset = iResults->Position();
            break;
            }
        case EQueryTypeEvent:
            {
            itemIds.iEventIds.iPtr.iCount = count;
            itemIds.iEventIds.iPtr.iOffset = iResults->Position();
            break;
            }
        case EQueryTypeRelation:
            {
            itemIds.iRelationIds.iPtr.iCount = count;
            itemIds.iRelationIds.iPtr.iOffset = iResults->Position();
            break;
            }
        default:
            {
#ifdef _DEBUG
			User::Panic( _L("MdSFOCr4") , KErrMdEUnknownQueryType );
#endif
			User::Leave( KErrMdEUnknownQueryType );
            }
        }

	iResults->PositionL( KNoOffset );
	itemIds.SerializeL( *iResults );

    for( TInt i = 0; i < count; i++ )
        {
	    AddIdToContainerL( iResultIds[i] );
        }
    }

void CMdSSqlFindOperation::CreateDistinctL()
	{
    TMdCItemIds itemIds;
    itemIds.iNamespaceDefId = iFindClause->NamespaceDef()->GetId();
    itemIds.iErrorCode = KErrNone;
    itemIds.iObjectIds.iPtr.iCount = 0;
    itemIds.iObjectIds.iPtr.iOffset = KNoOffset;
    itemIds.iEventIds.iPtr.iCount = 0;
    itemIds.iEventIds.iPtr.iOffset = KNoOffset;
    itemIds.iRelationIds.iPtr.iCount = 0;
    itemIds.iRelationIds.iPtr.iOffset = KNoOffset;

    itemIds.iObjectUris.iPtr.iCount = 0;
    itemIds.iObjectUris.iPtr.iOffset = sizeof(TMdCItemIds);
    
    iResults->PositionL( itemIds.iObjectUris.iPtr.iOffset );
    const TInt resultRowsCount = iResultRows.Count();
	for ( TInt i = 0; i < resultRowsCount; ++i )
		{		
		if ( !iResultRows[i]->Column( 0 ).IsNull() )
			{
			TPtrC16 value = TPtr16((TUint16*)0, 0);
			iResultRows[i]->Column( 0 ).Get( value );
			iResults->InsertL( value );
			++itemIds.iObjectUris.iPtr.iCount;
			}
		}

    iResults->PositionL( KNoOffset );
    itemIds.SerializeL( *iResults );
	}

void CMdSSqlFindOperation::AddToContainerL()
    {
    // if old result buffer exist try to use it
    if( iResults )
    	{
    	// create new if the old result buffer is too short
    	if( iResults->Size() < iMemoryLimit )
    		{
    		delete iResults;
    		iResults = NULL;

    		iResults = CMdCSerializationBuffer::NewL( iMemoryLimit );
    		}
    	// else just move to the begin of the result buffer
    	else
    		{
    		iResults->PositionL( 0 );
    		}
    	}
	else
		{
		iResults = CMdCSerializationBuffer::NewL( iMemoryLimit );
		}

    TInt err;
    switch( iResultMode )  
        {
        case EQueryResultModeCount:
            {
            TRAP( err, CreateCountL() );
            break;
            }
        case EQueryResultModeItem:
            {
            TRAP( err, CreateItemL() );
            break;
            }
        case EQueryResultModeId:
            {
            TRAP( err, CreateIdL() );
          break;
            }
        case EQueryResultModeDistinctValues:
            {
            TRAP( err, CreateDistinctL() );
            break;
            }
        default:
            {
#ifdef _DEBUG
			User::Panic( _L("MdSFOAd3") , KErrMdEUnknownQueryResultMode );
#endif
			User::Leave( KErrMdEUnknownQueryResultMode );
            }
        }
 
	if( err != KErrNone )
		{
		delete iResults;
		iResults = NULL;
		}

   	ConsumeRows();
    }

TMdCOffset CMdSSqlFindOperation::AddObjectToContainerL( RRowData& aRow, TMdCOffset aFreespaceOffset )
    {
    TMdCObject object;
    const TMdCOffset objectOffset = iResults->Position();
    object.iFlags = EMdEObjectFlagNone;

	// Get base objects basic values
    TUint32 serverSideFlags;
    TPtrC16 uri;
    aRow.Column( 0 ).Get( object.iId );
    aRow.Column( 1 ).Get( object.iDefId );
    aRow.Column( 2 ).Get( serverSideFlags );
    aRow.Column( 3 ).Get( object.iMediaId );
    aRow.Column( 4 ).Get( object.iUsageCount );
    aRow.Column( 5 ).Get( object.iGuidHigh );
    aRow.Column( 6 ).Get( object.iGuidLow );
    if (aRow.Column( 7 ).IsNull())
    	{
    	object.iId = KNoId;
    	object.iUri.iPtr.iCount = 0;
    	object.iUri.iPtr.iOffset = KNoOffset;
    	object.SerializeL( *iResults );
    	return aFreespaceOffset;
    	}
    aRow.Column( 7 ).Get( uri );

	// SETTING CLIENT SIDE FLAGS
	// Set not present flag to client side flags 
	// (removed objects are also flaged as not present)
	if( ( serverSideFlags & EMdEObjectFlagNotPresent ) ||
		( serverSideFlags & EMdEObjectFlagRemoved ) )
		{
		object.iFlags |= EMdEObjectFlagNotPresent;
		}

	// Set confidential flag to client side flags
	if( serverSideFlags & EMdEObjectFlagConfidential )
		{
		object.iFlags |= EMdEObjectFlagConfidential;
		}

	// Set freetext flag to client side flags
	if( serverSideFlags & EMdEObjectFlagFreetexts )
		{
		object.iFlags |= EMdEObjectFlagFreetexts;
		}

	// Set placeholder flag to client side flags
	if( serverSideFlags & EMdEObjectFlagPlaceholder )
		{
		object.iFlags |= EMdEObjectFlagPlaceholder;
		
		// object is placeholder, so try add it's URI to harverting 
		// prioritization buffer
		if( iHarvestingPrioritizationCount > 0 )
			{
			iFind.Server().AddHarvestingPrioritizationUriL( uri );

			iHarvestingPrioritizationCount--;

			if( iHarvestingPrioritizationCount == 0 )
				{
				iFind.Server().NotifyHarvestingPrioritizationObserver( KErrNone );
				}
			}
		}
	
	const CMdsObjectDef* objectDef = iFindClause->ObjectDef();
	if( !objectDef )
		{
#ifdef _DEBUG
		User::Panic( _L("MdSFOAd4") , KErrMdEUnknownObjectDef );
#endif		
		User::Leave( KErrMdEUnknownObjectDef );
		}

    // Add base objects basic values to result buffer
    object.iUri.iPtr.iCount = uri.Length();
    object.iUri.iPtr.iOffset = aFreespaceOffset;
    iResults->PositionL( aFreespaceOffset );
    aFreespaceOffset = iResults->InsertL( uri );

	const RPointerArray<CMdsPropertyDef>& propertyFilters = iFindClause->PropertyFilters();

	// No property filters
	if( propertyFilters.Count() <= 0 )
		{
		const TInt allPropertyCount = objectDef->GetAllPropertiesCount();
		object.iProperties.iPtr.iCount = 0;
		object.iProperties.iPtr.iOffset = aFreespaceOffset;

		// Position after property offsets
		aFreespaceOffset += allPropertyCount * sizeof(TMdCProperty);
		
		for( TInt i = 0; i < allPropertyCount; i++ )
			{
			const CMdsObjectDef::TMdsColumnOrder& propertyColumn = 
				objectDef->GetPropertyColumnL( i );

			TColumn& column = aRow.Column( propertyColumn.iColumnId );

			// check if property exists, else continue to with next property
			if( column.IsNull() )
				{
				continue;
				}

			TMdCProperty property;

			property.iPropertyDefId = propertyColumn.iPropertyDef.GetId();
			property.iModFlags = EMdEPropertyModNone;

			const TPropertyType propertyType = propertyColumn.iPropertyDef.GetType();
			switch(propertyType)
				{
				case EPropertyBool:
					{
					TBool value;
					column.Get( value );
					property.iValue.iInt32 = value;
					}
    				break;
    			case EPropertyInt8:
    				{
					TInt32 value32;
					column.Get( value32 );
					property.iValue.iInt32 = value32;
    				}
    				break;
    			case EPropertyUint8:
    				{
					TUint32 value32;
					column.Get( value32 );
					property.iValue.iUint32 = value32;
    				}
    				break;
    			case EPropertyInt16:
    				{
					TInt32 value32;
					column.Get( value32 );
					property.iValue.iInt32 = value32;
    				}
    				break;
    			case EPropertyUint16:
    				{
					TUint32 value32;
					column.Get( value32 );
					property.iValue.iUint32 = value32;
    				}
    				break;
    			case EPropertyInt32:
    				{
					TInt32 value;
					column.Get( value );
					property.iValue.iInt32 = value;
    				}
    				break;
    			case EPropertyUint32:
    				{
					TUint32 value;
					column.Get( value );
					property.iValue.iUint32 = value;
    				}
    				break;
				case EPropertyInt64:
    				{
					TInt64 value;
					column.Get( value );
					property.iValue.iInt64 = value;
    				}
    				break;    				
    			case EPropertyReal32:
    				{
					TReal32 value;
					column.Get( value );
					property.iValue.iReal = value;
    				}
    				break;
    			case EPropertyReal64:
    				{
					TReal64 value;
					column.Get( value );
					property.iValue.iReal = value;
    				}
    				break;
    			case EPropertyTime:
    				{
					TTime value;
					column.Get( value );
					property.iValue.iInt64 = value.Int64();
    				}
    				break;
    			case EPropertyText:
    				{    				
	    			TPtrC16 value;
					column.Get( value );
					if (value.Length() > 0)
						{
						property.iValue.iPtr.iCount = value.Length();
						property.iValue.iPtr.iOffset = aFreespaceOffset;
						iResults->PositionL( aFreespaceOffset );
						aFreespaceOffset = iResults->InsertL( value );
						}
					else
						{
						property.iValue.iPtr.iCount = 0;
						property.iValue.iPtr.iOffset = KNoOffset;
						}
    				}
    				break;
    			default:
#ifdef _DEBUG
					User::Panic( _L("MdSFOAd5") , KErrMdEUnknownPropertyType );
#endif
					User::Leave( KErrMdEUnknownPropertyType );
				}

		    // store property in buffer
			iResults->PositionL( object.iProperties.iPtr.iOffset
					+ object.iProperties.iPtr.iCount * sizeof(TMdCProperty) );
			++object.iProperties.iPtr.iCount;
		    property.SerializeL( *iResults );
			}
		}
	// Property filters
	else
		{
		const TUint32 propertyCount = propertyFilters.Count();
		object.iProperties.iPtr.iCount = 0;
		object.iProperties.iPtr.iOffset = aFreespaceOffset;

		// Position after property offsets
		aFreespaceOffset += propertyCount * sizeof(TMdCProperty);

		for( TInt i = 0; i < propertyCount; i++ )
			{
			CMdsPropertyDef* propDef = propertyFilters[i];

			if( !propDef )
				{
#ifdef _DEBUG
				User::Panic( _L("MdSFOAd6") , KErrMdEUnknownPropertyDef );
#endif
				User::Leave( KErrMdEUnknownPropertyDef );
				}

			TColumn& column = aRow.Column( KBaseObjectBasicValueColumnOffset + i );

			// check if property exists, else continue to with next property
			if( column.IsNull() )
				{
				continue;
				}

			TMdCProperty property;

			property.iPropertyDefId = propDef->GetId();
			property.iModFlags = EMdEPropertyModNone;

			const TPropertyType propertyType = propDef->GetType();
			switch(propertyType)
				{
				case EPropertyBool:
					{
					TBool value;
					column.Get( value );
					property.iValue.iInt32 = value;
					}
					break;
				case EPropertyInt8:
					{
					TInt32 value32;
					column.Get( value32 );
					property.iValue.iInt32 = value32;
					}
					break;
				case EPropertyUint8:
					{
					TUint32 value32;
					column.Get( value32 );
					property.iValue.iUint32 = value32;
					}
					break;
				case EPropertyInt16:
					{
					TInt32 value32;
					column.Get( value32 );
					property.iValue.iInt32 = value32;
					}
					break;
				case EPropertyUint16:
					{
					TUint32 value32;
					column.Get( value32 );
					property.iValue.iUint32 = value32;
					}
					break;
				case EPropertyInt32:
					{
					TInt32 value;
					column.Get( value );
					property.iValue.iInt32 = value;
					}
					break;
				case EPropertyUint32:
					{
					TUint32 value;
					column.Get( value );
					property.iValue.iUint32 = value;
					}
					break;
				case EPropertyInt64:
					{
					TInt64 value;
					column.Get( value );
					property.iValue.iInt64 = value;
					}
					break;    				
				case EPropertyReal32:
					{
					TReal32 value;
					column.Get( value );
					property.iValue.iReal = value;
					}
					break;
				case EPropertyReal64:
					{
					TReal64 value;
					column.Get( value );
					property.iValue.iReal = value;
					}
					break;
				case EPropertyTime:
					{
					TTime value;
					column.Get( value );
					property.iValue.iReal = value.Int64();
					}
					break;
				case EPropertyText:
					{    				
	    			TPtrC16 value;
					column.Get( value );
					if (value.Length() > 0)
						{
						property.iValue.iPtr.iCount = value.Length();
						property.iValue.iPtr.iOffset = aFreespaceOffset;
						iResults->PositionL( aFreespaceOffset );
						aFreespaceOffset = iResults->InsertL( value );
						}
					else
						{
						property.iValue.iPtr.iCount = 0;
						property.iValue.iPtr.iOffset = KNoOffset;
						}
					}
					break;
				default:
#ifdef _DEBUG
					User::Panic( _L("MdSFOAd7") , KErrMdEUnknownPropertyType );
#endif
					User::Leave( KErrMdEUnknownPropertyType );
				}

		    // store property in buffer
			iResults->PositionL( object.iProperties.iPtr.iOffset
					+ object.iProperties.iPtr.iCount * sizeof(TMdCProperty) );
			++object.iProperties.iPtr.iCount;
		    property.SerializeL( *iResults );
			}
		}

	if( FindCriteria().IncludesFreetexts() )
		{		
		// In result row the second lastest column is free text count
		const TInt freeTextCountColumn = aRow.Size() - 2;

		// Get free text count and total free text lenght.
		TUint32 freeTextCount = 0;
		aRow.Column( freeTextCountColumn ).Get( freeTextCount );

		if( freeTextCount > 0 )
			{
			object.iFreeTexts.iPtr.iCount = freeTextCount;
			object.iFreeTexts.iPtr.iOffset = aFreespaceOffset;
			
			// In result row last column is total free text lenght.
			const TInt totalFreeTextsLengthColumn = aRow.Size() - 1;

			TUint32 totalFreeTextsLength = 0;
			aRow.Column( totalFreeTextsLengthColumn ).Get( totalFreeTextsLength );

			// Reserve space for free texts.
			// For every free text possible padding (TUint8), length (TUint16)
			TUint32 freeTextReserve = freeTextCount * CMdCSerializationBuffer::KRequiredSizeForEmptyText;
			// and total free text length * TUint16
			freeTextReserve += totalFreeTextsLength * sizeof( TUint16 );

			aFreespaceOffset += freeTextReserve;
			}
		else
			{
			object.iFreeTexts.iPtr.iCount = 0;
			object.iFreeTexts.iPtr.iOffset = KNoOffset;
			}
		}
	else
		{
		object.iFreeTexts.iPtr.iCount = 0;
		object.iFreeTexts.iPtr.iOffset = KNoOffset;
		}

	iResults->PositionL( objectOffset );
    object.SerializeL( *iResults );

	return aFreespaceOffset;
    }

void CMdSSqlFindOperation::ConsumeRows()
    {
	if( EQueryResultModeId != iResultMode )
		{    
	    for( TInt i = iResultRows.Count() - 1; i >=0; i-- )
	    	{
	    	iResultRows[i]->Close();
	    	}

	    iResultRows.ResetAndDestroy();
		}
	// handle result mode IDs as special case
	else
		{
		iResultIds.Reset();
		}
	}