metadataengine/server/src/mdssqlobjectmanipulate.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 25 May 2010 13:10:05 +0300
branchRCL_3
changeset 13 4a4892eec172
parent 9 82c0024438c8
child 19 b73252188534
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

/*
* Copyright (c) 2002-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:  Add, update and remove items in DB.
*                 Basic DB manipulation engine.
*
*/

#include "mdssqlobjectmanipulate.h"

#include "mdcitem.h"
#include "mdsdbconnectionpool.h"
#include "mdssqliteconnection.h"
#include "mdsfindsqlclausedef.h"
#include "mdsschema.h"
#include "mdsnamespacedef.h"
#include "mdsobjectdef.h"
#include "mdspropertydef.h"
#include "mdsclausebuffer.h"
#include "mdsobjectlocklist.h"
#include "mdsindexer.h"
#include "mdspreferences.h"
#include "mdslogger.h"
#include "mdcserializationbuffer.h"
#include "mdssqldbmaintenance.h"
#include "mdcresult.h"
#include "mdeinternalerror.h"

#include "mdsgetimeiao.h"

#include <e32math.h>
#include <mdeobject.h>

/** logging instance */
__USES_LOGGER

const TInt KMaxBuffers = 5;

_LIT( KMemoryCard, "MC" );


//------------------------------------------------------------------------------------
// CLASS      CMdSSqlObjectManipulate
//------------------------------------------------------------------------------------

CMdSIdentifierGenerator* CMdSIdentifierGenerator::NewL( )
    {
    CMdSIdentifierGenerator* self = CMdSIdentifierGenerator::NewLC( );
    CleanupStack::Pop( self );
    return self;
    }

CMdSIdentifierGenerator* CMdSIdentifierGenerator::NewLC( )
    {
    CMdSIdentifierGenerator* self = new ( ELeave ) CMdSIdentifierGenerator( );
    CleanupStack::PushL( self );
    self->ConstructL( );
    return self;
    }

CMdSIdentifierGenerator::~CMdSIdentifierGenerator()
    {
    delete iDigest;
    }

void CMdSIdentifierGenerator::ConstructL( )
    {
    CMdsGetImeiAO * imeigetter = CMdsGetImeiAO::NewLC();
    iImei = imeigetter->GetIMEI();
    
    TTime uTime;
    uTime.UniversalTime();
    TInt64 intTime = uTime.Int64();
    TUint32 rand = Math::Rand( intTime );

    iImei ^= (TInt64)(rand & 0xFF000000) << ( sizeof( TUint32 ) * 8 );
    
    CleanupStack::PopAndDestroy(imeigetter);
    iLastTime = 0;
    
    iDigest = CMessageDigestFactory::NewDigestL( CMessageDigest::EMD5 );
    }

void CMdSIdentifierGenerator::GenerateGuid( TInt64& aGuidHigh, TInt64& aGuidLow )
	{
	if (aGuidHigh == 0 && aGuidLow == 0)
		{
		TTime currTime;
		currTime.UniversalTime();
		const TInt64 tickCount = currTime.Int64();
		if (iLastTime < tickCount)
			{
			iLastTime = tickCount;
			}
		else
			{
			++iLastTime;
			}

		//MD5 hash GUID
		const TInt64 KXorImei = I64LIT( 0x2C3E773D1A25916E );
		const TInt64 xorImei = iImei ^ KXorImei;

		const TInt KMaxQuidLength = 16;
		TBuf8<KMaxQuidLength> message;
		message.SetLength( KMaxQuidLength );
		Mem::Copy( (TAny*)( message.Ptr() ), &xorImei, sizeof( TInt64 ) );
		Mem::Copy( (TAny*)( message.Ptr() + sizeof( TInt64 ) ), &iLastTime, sizeof( TInt64 ) );

		TPtrC8 hash = iDigest->Final( message );

		__ASSERT_DEBUG( hash.Size() >= KMaxQuidLength, User::Panic( _L("CMdSIdentifierGenerator::GenerateGuid"), KErrGeneral ) );

		Mem::Copy( &aGuidHigh, hash.Ptr(), sizeof( TInt64 ) );
		Mem::Copy( &aGuidLow, hash.Ptr() + sizeof( TInt64 ), sizeof( TInt64 ) );
		//MD5 hash GUID end
		}
	}

HBufC* CMdSIdentifierGenerator::GenerateUriL( const CMdsObjectDef& aObjectDef, 
		const TInt64& aGuidHigh, const TInt64& aGuidLow ) const
	{
	_LIT( KDot, "." );
	HBufC* uri = HBufC::NewLC( aObjectDef.GetName().Length() + 2 /*two dots*/+ 
			2*KMaxUint64ValueLength );

	TPtr uriPtr( uri->Des() );
	uriPtr.Append( aObjectDef.GetName() );
	uriPtr.Append( KDot );
	uriPtr.AppendNum( aGuidHigh );
	uriPtr.Append( KDot );
	uriPtr.AppendNum( aGuidLow );
	CleanupStack::Pop( uri );
	return uri;
	}


//-----------------------------------------------------------------------------
// CLASS      CMdSSqlObjectManipulate
//-----------------------------------------------------------------------------

CMdSSqlObjectManipulate* CMdSSqlObjectManipulate::NewL( 
		const CMdsSchema& aSchema, CMdSObjectLockList& aLockList )
    {
    CMdSSqlObjectManipulate* self = CMdSSqlObjectManipulate::NewLC( aSchema, 
    		aLockList );
    CleanupStack::Pop( self );
    return self;
    }

CMdSSqlObjectManipulate* CMdSSqlObjectManipulate::NewLC( 
		const CMdsSchema& aSchema, CMdSObjectLockList& aLockList )
    {
    CMdSSqlObjectManipulate* self = new ( ELeave ) CMdSSqlObjectManipulate( 
    		aSchema, aLockList );
    CleanupStack::PushL( self );
    self->ConstructL( );
    return self;
    }

CMdSSqlObjectManipulate::~CMdSSqlObjectManipulate()
    {
    // doesn't own namespace definition
	iNamespaceDef = NULL;

	const TInt count = iBuffers.Count();
	
	for (TInt i = 0; i < count; ++i)
		{
		delete iBuffers[i].iBuffer;
		}
	iBuffers.Close();

	delete iGenerator;
	delete iUri;
    }

CMdSSqlObjectManipulate::CMdSSqlObjectManipulate( const CMdsSchema& aSchema, 
		CMdSObjectLockList& aLockList )
	: iSchema( aSchema ), iGenerator(NULL), iLockList( aLockList ) 
    {
    }

void CMdSSqlObjectManipulate::ConstructL( )
    {
	iGenerator = CMdSIdentifierGenerator::NewL();

	iNamespaceDef = NULL;
	
	for (TInt i = 0; i < KMaxBuffers; ++i)
		{
	    TLockBuffer lockBuffer;
	    lockBuffer.iLock = EFalse;
	    lockBuffer.iBuffer = CMdsClauseBuffer::NewLC( 1024 );
		iBuffers.AppendL( lockBuffer );
		CleanupStack::Pop(); // buffer
		}
    }

TBool CMdSSqlObjectManipulate::GarbageCollectionL()
	{
	return DoGarbageCollectionL();
	}

void CMdSSqlObjectManipulate::SetNamespace( 
		const CMdsNamespaceDef* aNamespaceDef )
	{
	iNamespaceDef = aNamespaceDef;
	}

void CMdSSqlObjectManipulate::AddMemoryCardL(TUint32 aMediaId)
	{
	TTime currentTime;
	currentTime.UniversalTime();

	TInt modifiedRowCount = MMdsPreferences::UpdateL( KMemoryCard, 
			MMdsPreferences::EPreferenceExtraSet, aMediaId, 
			currentTime.Int64() );

	if( modifiedRowCount <= 0 )
		{
		MMdsPreferences::InsertL( KMemoryCard, 
								  MMdsPreferences::EPreferenceBothSet, 
								  aMediaId, currentTime.Int64() );
		}
	}

void CMdSSqlObjectManipulate::GetMemoryCardL(TUint32& aMediaId)
	{
	TInt rowCount = MMdsPreferences::GetL( KMemoryCard, 
										   MMdsPreferences::EPreferenceValueGet | MMdsPreferences::EPreferenceExtraSortDesc, 
								  		   aMediaId );

	// if no rows found leave
	if( rowCount <= 0 )
		{
		User::Leave( KErrNotFound );
		}
	}

TBool CMdSSqlObjectManipulate::CheckMemoryCardL(TUint32 aMediaId)
	{
	TInt rowCount = MMdsPreferences::GetL( KMemoryCard, 
										   MMdsPreferences::EPreferenceValueGet | MMdsPreferences::EPreferenceValueSet, 
								  		   aMediaId );

	if( rowCount > 0 )
		{
		return ETrue;
		}
	return EFalse;
	}


void CMdSSqlObjectManipulate::SetMediaL(TUint32 aMediaId, TChar aDrive,
		TBool aPresentState)
	{
	_LIT( KInsertMedia, "INSERT OR REPLACE INTO MdS_Medias VALUES(?,?,?,?);" );

	RClauseBuffer commonClause( *this, KInsertMedia.iTypeLength );
	CleanupClosePushL( commonClause );
	CMdsClauseBuffer& clauseBuffer = commonClause.BufferL();
	clauseBuffer.BufferL() = KInsertMedia;

	TTime currentTime;
	currentTime.UniversalTime();
	const TInt64 currentTime64 = currentTime.Int64();
	
    RRowData var;
    CleanupClosePushL( var );
    var.ReserveL( 4 ); // reserve space for media ID, drive, present state and time
    var.AppendL( TColumn( aMediaId ) );
    var.AppendL( TColumn( (TInt32)aDrive ) );
    var.AppendL( TColumn( aPresentState ) );
    var.AppendL( TColumn( currentTime64 ) );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	connection.ExecuteL( clauseBuffer.ConstBufferL(), var );

	CleanupStack::PopAndDestroy( 2, &commonClause ); // var, commonClauseOne
	}

TBool CMdSSqlObjectManipulate::GetMediaL(TUint32 aMediaId, TChar& aDrive, 
		TBool& aPresentState)
	{
	_LIT( KGetMedia, "SELECT Drive, PresentState FROM MdS_Medias WHERE MediaId=?;" );

	RClauseBuffer commonClause( *this, KGetMedia.iTypeLength );
	CleanupClosePushL( commonClause );
	CMdsClauseBuffer& clauseBuffer = commonClause.BufferL();
	clauseBuffer.BufferL() = KGetMedia;

    RRowData var;
    CleanupClosePushL( var );
    var.AppendL( TColumn( aMediaId ) );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	RMdsStatement statement;
	CleanupClosePushL( statement );
	connection.ExecuteQueryL( clauseBuffer.ConstBufferL(), statement, var );

	var.Free();
	var.Reset();

	TInt32 drive = 0;
	
    var.ReserveL( 2 ); // reserve space for drive and present state
	var.AppendL( TColumn( drive ) );
	var.AppendL( TColumn( aPresentState ) );

	TBool found = EFalse;

	if( connection.NextRowL( statement, var ) )
		{
		var.Column( 0 ).Get( drive );
		var.Column( 1 ).Get( aPresentState );
		
		aDrive = drive;
		
		found = ETrue;
		}

	CleanupStack::PopAndDestroy( 3, &commonClause ); // statement, var, commonClauseOne

	return found;
	}

TInt32 CMdSSqlObjectManipulate::GetPresentMediasL(TDes8& aMediaInfoBuffer)
	{
	_LIT( KGetPresentMedias, "SELECT MediaId, Drive FROM MdS_Medias WHERE PresentState!=?;" );

	RClauseBuffer commonClause( *this, KGetPresentMedias.iTypeLength );
	CleanupClosePushL( commonClause );
	CMdsClauseBuffer& clauseBuffer = commonClause.BufferL();
	clauseBuffer.BufferL() = KGetPresentMedias;

	const TBool notPresentState = EFalse;

    RRowData var;
    CleanupClosePushL( var );
    var.AppendL( TColumn( notPresentState ) );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	RMdsStatement statement;
	CleanupClosePushL( statement );
	connection.ExecuteQueryL( clauseBuffer.ConstBufferL(), statement, var );

	var.Free();
	var.Reset();

	TUint32 mediaId = 0;
	TInt32 drive = 0;

    var.ReserveL( 2 ); // reserve space for drive and present state
	var.AppendL( TColumn( mediaId ) );
	var.AppendL( TColumn( drive ) );

	TInt32 count = 0;

	TInt bufferPosition = 0;
	
	const TInt lastBufferPosition = aMediaInfoBuffer.MaxSize() - sizeof( TMdEMediaInfo );

	const TUint8* aMediaInfoBufferPtr = aMediaInfoBuffer.Ptr();
	
	while( connection.NextRowL( statement, var ) )
		{
		var.Column( 0 ).Get( mediaId );
		var.Column( 1 ).Get( drive );
		
		TMdEMediaInfo mediaInfo;
		mediaInfo.iMediaId = mediaId;
		mediaInfo.iDrive = drive;

		if( bufferPosition > lastBufferPosition )
			{
			User::Leave( KErrBadDescriptor );
			}
	
		TUint8* ptr = (TUint8*)( aMediaInfoBufferPtr + bufferPosition );
		
		Mem::Copy( ptr, &mediaInfo, sizeof( TMdEMediaInfo ) );
		
		bufferPosition += sizeof( TMdEMediaInfo );
		
		++count;
		}
	
	aMediaInfoBuffer.SetLength( bufferPosition );

	CleanupStack::PopAndDestroy( 3, &commonClause ); // statement, var, commonClauseOne

	return count;
	}

TItemId CMdSSqlObjectManipulate::SearchNotPresentFileL(TUint32 aMediaId, 
		TDesC16& aUri, TMdSFileInfo& aFileInfo,
		TFilePresentStates& aPlaceHolder, TBool& aNotPresentState)
	{
	_LIT( KSearchNotPresentFile, "SELECT ObjectId, Flags, LastModifiedDate, Size FROM Object%u WHERE NOT Flags&? AND (Flags&? OR Flags&? OR Flags&? ) AND MediaId=? AND URI=?;" );

	RClauseBuffer commonClauseOne(*this, KSearchNotPresentFile.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseBuffer = commonClauseOne.BufferL();
	clauseBuffer.BufferL().Format( KSearchNotPresentFile, KDefaultNamespaceDefId );

	TItemId objectId = KNoId;
	TUint32 flags = 0;

    RRowData var;
    CleanupClosePushL( var );
    var.ReserveL( 6 );
    var.AppendL( TColumn( EMdEObjectFlagRemoved ) );
    var.AppendL( TColumn( EMdEObjectFlagNotPresent ) ); // not present flag
    var.AppendL( TColumn( EMdEObjectFlagStartUpNotPresent ) ); // start up not present flag
    var.AppendL( TColumn( EMdeObjectFlagPending ) ); // pending for composing - needed to complete composing
    var.AppendL( TColumn( aMediaId ) );
    var.AppendL( TColumn( aUri ) );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	RMdsStatement statement;
	CleanupClosePushL( statement );
    connection.ExecuteQueryL( clauseBuffer.ConstBufferL(), statement, var );

    TInt64 modifiedTime(0);
    TUint32 size(0);

    RRowData result;
    CleanupClosePushL( result );
    result.ReserveL( 4 );
    result.AppendL( TColumn( objectId ) );
    result.AppendL( TColumn( flags ) );
    result.AppendL( TColumn( modifiedTime ) );
    result.AppendL( TColumn( size ) );

    // default values (used if object doesn't exist)
	aPlaceHolder = EMdsNotFound;
	aNotPresentState = EFalse;

	if( connection.NextRowL( statement, result ) )
		{
		result.Column( 0 ).Get( objectId );
		result.Column( 1 ).Get( flags );

		if ( flags & EMdEObjectFlagPlaceholder )
			{
			aPlaceHolder = EMdsPlaceholder;
			}
		else
			{
			result.Column( 2 ).Get( modifiedTime );
			result.Column( 3 ).Get( size );

			// check if file is modified
    		if ( ( aFileInfo.iModifiedTime == modifiedTime ) && ( aFileInfo.iSize == size ) )
    			{
    			aPlaceHolder = EMdsNormal;
    			
    	        // If images were pending for composing, composer needs to be notified for the composing to complete 
    	        if( (flags & EMdeObjectFlagPending) && (flags & EMdEObjectFlagStartUpNotPresent) )
    	            {
    	            aNotPresentState = ETrue;
    	            }
    			}
    		else
    			{
    			aPlaceHolder = EMdsModified;
    			}
			}

		if( flags & EMdEObjectFlagNotPresent )
			{
			aNotPresentState = ETrue;
			}
		}

	CleanupStack::PopAndDestroy( &result );
	CleanupStack::PopAndDestroy( &statement );
	CleanupStack::PopAndDestroy( &var );
	CleanupStack::PopAndDestroy( &commonClauseOne );
	return objectId;
	}

void CMdSSqlObjectManipulate::SetFilesToPresentL(const RArray<TItemId>& aObjectIds)
	{
	const TInt objectCount = aObjectIds.Count();
    if ( objectCount > 0 )
    	{
		_LIT( KSetFileToPresent, "UPDATE Object%u SET Flags=Flags&? WHERE (Flags&?)<>0 AND ObjectId IN (?" );
		_LIT( KCommaQuestionmark, ",?");
		_LIT( KBracketSemicolon, ");");
		
		RClauseBuffer commonClauseOne(*this, KSetFileToPresent.iTypeLength + KMaxUintValueLength +
				( KCommaQuestionmark.iTypeLength * ( objectCount-1 ) ) +
				KBracketSemicolon.iTypeLength );
		CleanupClosePushL( commonClauseOne );
		CMdsClauseBuffer& clauseBuffer = commonClauseOne.BufferL();
		clauseBuffer.BufferL().Format( KSetFileToPresent, KDefaultNamespaceDefId );

	    RRowData var;
	    var.ReserveL( 3 );
	    CleanupClosePushL( var );
	    // reset not present and start up not present flags
	    var.AppendL( TColumn( ~(EMdEObjectFlagNotPresent | EMdEObjectFlagStartUpNotPresent) ) );
	    var.AppendL( TColumn( (EMdEObjectFlagNotPresent | EMdEObjectFlagStartUpNotPresent) ) );
	    var.AppendL( TColumn( aObjectIds[0] ) );

	    for ( TInt i = 1; i < objectCount; i++ )
	    	{
	    	clauseBuffer.AppendL( KCommaQuestionmark );
		    var.AppendL( TColumn( aObjectIds[i] ) );
	    	}
	    
	    clauseBuffer.AppendL( KBracketSemicolon );
	    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	    connection.ExecuteL( clauseBuffer.ConstBufferL(), var );
	
		CleanupStack::PopAndDestroy( &var );
		CleanupStack::PopAndDestroy( &commonClauseOne ); 
    	}
	}

void CMdSSqlObjectManipulate::SetRelationsToPresentL(TItemId aObjectId, 
		RArray<TItemId>& aIdArray)
	{
	_LIT( KSearchNotPresentRelations, "SELECT RelationId FROM Relations%u WHERE NOT Flags&? AND Flags&? AND LeftObjectId=? UNION SELECT RelationId FROM Relations%u WHERE NOT Flags&? AND Flags&? AND RightObjectId=?;" );
	_LIT( KSetRelationsToPresent1, "UPDATE Relations%u SET Flags=Flags&? WHERE Flags&? AND LeftObjectId=?;" );
	_LIT( KSetRelationsToPresent2, "UPDATE Relations%u SET Flags=Flags&? WHERE Flags&? AND RightObjectId=?;" );

	RClauseBuffer commonClauseOne(*this, KSearchNotPresentRelations.iTypeLength + 2*KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseBuffer = commonClauseOne.BufferL();
	clauseBuffer.BufferL().Format( KSearchNotPresentRelations, KDefaultNamespaceDefId, KDefaultNamespaceDefId );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
    RRowData var;
    CleanupClosePushL( var );
    
    var.ReserveL( 6 ); // reserve space for flags and object IDs
    var.AppendL( TColumn( EMdERelationFlagDeleted ) );
    var.AppendL( TColumn( EMdERelationFlagNotPresent ) );
    var.AppendL( TColumn( aObjectId ) );
    var.AppendL( TColumn( EMdERelationFlagDeleted ) );
    var.AppendL( TColumn( EMdERelationFlagNotPresent ) );
    var.AppendL( TColumn( aObjectId ) );

	RMdsStatement statement;
	CleanupClosePushL( statement );
	connection.ExecuteQueryL( clauseBuffer.ConstBufferL(), statement, var );

	var.Free();	
	var.Reset();
    TItemId relationId(0);
    var.AppendL( TColumn( relationId ) );
	while( connection.NextRowL( statement, var ) )
		{
		var.Column( 0 ).Get( relationId );
		aIdArray.AppendL( relationId );
		}

	clauseBuffer.ReserveSpaceL( KSetRelationsToPresent1.iTypeLength + KMaxUintValueLength );
	clauseBuffer.BufferL().Format( KSetRelationsToPresent1, KDefaultNamespaceDefId );

    var.Free(); 
    var.Reset();

    var.ReserveL( 3 );
    var.AppendL( TColumn( ~EMdERelationFlagNotPresent ) ); // reset not present flag
    var.AppendL( TColumn( EMdERelationFlagNotPresent ) );
    var.AppendL( TColumn( aObjectId ) );

    connection.ExecuteL( clauseBuffer.ConstBufferL(), var );

    clauseBuffer.ReserveSpaceL( KSetRelationsToPresent2.iTypeLength + KMaxUintValueLength );
    clauseBuffer.BufferL().Format( KSetRelationsToPresent2, KDefaultNamespaceDefId );

    var.Free(); 
    var.Reset();

    var.AppendL( TColumn( ~EMdERelationFlagNotPresent ) ); // reset not present flag
    var.AppendL( TColumn( EMdERelationFlagNotPresent ) );
    var.AppendL( TColumn( aObjectId ) );

    connection.ExecuteL( clauseBuffer.ConstBufferL(), var );
    
	CleanupStack::PopAndDestroy( 3, &commonClauseOne ); // statement, var, clauseBuffer
	}

void CMdSSqlObjectManipulate::SetFilesToNotPresentL(TUint32 aMediaId, TBool aStartUp,
		RArray<TItemId>& aObjectIds)
	{	
	_LIT( KSearchPresentFilesStartUpL, "SELECT ObjectId FROM Object%u WHERE NOT Flags&? AND MediaId=?;" );
	_LIT( KSearchPresentFilesL, "SELECT ObjectId FROM Object%u WHERE NOT Flags&? AND NOT Flags&? AND MediaId=?;" );
	
	RClauseBuffer commonClauseOne(*this, ( aStartUp ? KSearchPresentFilesStartUpL.iTypeLength : KSearchPresentFilesL.iTypeLength )+ 
			KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseBuffer = commonClauseOne.BufferL();
	
	if( aStartUp )
		{
		clauseBuffer.BufferL().Format( KSearchPresentFilesStartUpL, KDefaultNamespaceDefId );
		}
	else
		{
		clauseBuffer.BufferL().Format( KSearchPresentFilesL, KDefaultNamespaceDefId );
		}

	TItemId objectId = 0;

    RRowData var;
    CleanupClosePushL( var );
    
    var.ReserveL( 3 ); // reserve space for flags and media ID
    var.AppendL( TColumn( EMdEObjectFlagRemoved ) );
    if ( !aStartUp )
    	{
    	var.AppendL( TColumn( EMdEObjectFlagNotPresent ) ); // present flag
    	}
    var.AppendL( TColumn( aMediaId ) );

	RMdsStatement statement;
	CleanupClosePushL( statement );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

    connection.ExecuteQueryL( clauseBuffer.ConstBufferL(), statement, var );

    var.Free(); 
    var.Reset();

    var.AppendL( TColumn( objectId ) );
	while( connection.NextRowL( statement, var ) )
		{
		var.Column( 0 ).Get( objectId );
		aObjectIds.AppendL( objectId );
		}

    var.Free(); 
    var.Reset();
	
	if( aStartUp )
	    {
        _LIT( KSetFilesToNotPresentBoot, "UPDATE Object%u SET Flags=Flags|? WHERE MediaId=?;" );
        clauseBuffer.ReserveSpaceL( 
                KSetFilesToNotPresentBoot.iTypeLength + 
                KMaxUintValueLength ); // TUint32 max value's lenght is 10 numbers so %u + 8
        clauseBuffer.BufferL().Format( KSetFilesToNotPresentBoot, KDefaultNamespaceDefId );

        var.AppendL( TColumn( EMdEObjectFlagStartUpNotPresent ) ); // set not present flag
	    }
	else
	    {
        _LIT( KSetFilesToNotPresent, "UPDATE Object%u SET Flags=Flags|? WHERE NOT (Flags&?)<>0 AND MediaId=?;" );
        clauseBuffer.ReserveSpaceL( 
                KSetFilesToNotPresent.iTypeLength + 
                KMaxUintValueLength ); // TUint32 max value's lenght is 10 numbers so %u + 8
        clauseBuffer.BufferL().Format( KSetFilesToNotPresent, KDefaultNamespaceDefId );

        var.AppendL( TColumn( EMdEObjectFlagNotPresent ) ); // set not present flag	
        var.AppendL( TColumn( EMdEObjectFlagNotPresent ) ); // check not present flag 
	    }

	var.AppendL( TColumn( aMediaId ) );

    connection.ExecuteL( clauseBuffer.ConstBufferL(), var );

    // statement, var, commonClauseOne
	CleanupStack::PopAndDestroy( 3, &commonClauseOne );
	}

void CMdSSqlObjectManipulate::SetRelationsToNotPresentL(
		TUint32 aMediaId, RArray<TItemId>& aRelationIds)
	{
	_LIT( KSearchPresentRelations, "SELECT A.RelationId FROM Relations%u AS A, Object%u AS B WHERE A.LeftObjectId = B.ObjectId AND B.MediaId=%u AND NOT A.Flags&%u AND NOT A.Flags&%u UNION SELECT A.RelationId FROM Relations%u AS A, Object%u AS B WHERE A.RightObjectId = B.ObjectId AND B.MediaId=%u AND NOT A.Flags&%u AND NOT A.Flags&%u" );
	_LIT( KSetRelationsToPresent, "UPDATE Relations%u SET Flags=Flags|? WHERE NOT Flags&? AND RelationId IN (%S);" );

	// RelationIDs query sql statement
	RClauseBuffer commonClauseOne(*this, 
			KSearchPresentRelations.iTypeLength + 
			10*KMaxUintValueLength  );
    CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseBufferOne = commonClauseOne.BufferL();
	clauseBufferOne.BufferL().Format( KSearchPresentRelations, 
                KDefaultNamespaceDefId,
                KDefaultNamespaceDefId,
                aMediaId,
                EMdERelationFlagDeleted,
                EMdERelationFlagNotPresent,
                KDefaultNamespaceDefId,
                KDefaultNamespaceDefId,
                aMediaId,
                EMdERelationFlagDeleted,
                EMdERelationFlagNotPresent
                );
	
    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
    	
    RRowData var;
    CleanupClosePushL( var );
    
	RMdsStatement statement;
	CleanupClosePushL( statement );

	connection.ExecuteQueryL( clauseBufferOne.ConstBufferL(), statement, var );

    // Get RelationIDs From query result
    TItemId relationId(0);
    var.AppendL( TColumn( relationId ) );
	while( connection.NextRowL( statement, var ) )
		{
		var.Column( 0 ).Get( relationId );
		aRelationIds.AppendL( relationId );
		}
	
    // Set objects' relations not present by MediaID
	RClauseBuffer commonClauseTwo(*this, 
			KSetRelationsToPresent.iTypeLength + 			 
            KMaxUintValueLength +
			clauseBufferOne.ConstBufferL().Length() );
	
    CleanupClosePushL( commonClauseTwo );
	CMdsClauseBuffer& clauseBufferTwo = commonClauseTwo.BufferL();
	clauseBufferTwo.BufferL().Format( KSetRelationsToPresent, 
                                   KDefaultNamespaceDefId,
                                   &clauseBufferOne.ConstBufferL() );

	var.Free();
	var.Reset();
    var.ReserveL( 2 ); 
    var.AppendL( TColumn( EMdERelationFlagNotPresent ) );
    var.AppendL( TColumn( EMdERelationFlagNotPresent ) );

    connection.ExecuteL( clauseBufferTwo.ConstBufferL(), var );

    // commonClauseTwo, statement, var, commonClauseOne
	CleanupStack::PopAndDestroy( 4, &commonClauseOne );
	}

void CMdSSqlObjectManipulate::RemoveFilesNotPresentL(TUint32 aMediaId, RArray<TItemId>* aObjectIds)
	{
	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	
	// collect object IDs from start up not present objects
	if( aObjectIds )
		{
		_LIT( KSelectFilesStartUpNotPresent, "SELECT ObjectId FROM Object%u WHERE NOT Flags&? AND NOT Flags&? AND Flags&? AND MediaId=?;" );

		RClauseBuffer commonClauseOne(*this, 
				KSelectFilesStartUpNotPresent.iTypeLength + KMaxUintValueLength );
		CleanupClosePushL( commonClauseOne );
		CMdsClauseBuffer& clauseBuffer = commonClauseOne.BufferL();

		clauseBuffer.BufferL().Format( KSelectFilesStartUpNotPresent, KDefaultNamespaceDefId );

		RRowData var;
		CleanupClosePushL( var );
		var.ReserveL( 4 );
		var.AppendL( TColumn( EMdEObjectFlagRemoved ) );
		var.AppendL( TColumn( EMdEObjectFlagNotPresent ) );
		var.AppendL( TColumn( EMdEObjectFlagStartUpNotPresent ) );
		var.AppendL( TColumn( aMediaId ) );

		RMdsStatement statement;
		CleanupClosePushL( statement );
	    connection.ExecuteQueryL( clauseBuffer.ConstBufferL(), statement, var );

		RRowData result;
	    CleanupClosePushL( result );
	    TItemId objectId( KNoId );
	    result.AppendL( TColumn( objectId ) );

		while( connection.NextRowL( statement, result ) )
			{
			result.Column( 0 ).Get( objectId );
			aObjectIds->AppendL( objectId );
			}

		CleanupStack::PopAndDestroy( &result );
		CleanupStack::PopAndDestroy( &statement );
		CleanupStack::PopAndDestroy( &var );
		CleanupStack::PopAndDestroy( &commonClauseOne );
		}

	_LIT( KRemoveFilesNotPresent, "UPDATE Object%u SET Flags=Flags|? WHERE NOT Flags&? AND (Flags&? OR Flags&?) AND MediaId=?;" );

	RClauseBuffer commonClauseOne(*this, 
			KRemoveFilesNotPresent.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseBuffer = commonClauseOne.BufferL();
	clauseBuffer.BufferL().Format( KRemoveFilesNotPresent, KDefaultNamespaceDefId );

    RRowData var;
    CleanupClosePushL( var );
    var.ReserveL( 5 ); 
    var.AppendL( TColumn( EMdEObjectFlagRemoved ) );
    var.AppendL( TColumn( EMdEObjectFlagRemoved ) );
    var.AppendL( TColumn( EMdEObjectFlagNotPresent ) ); // not present flag
    var.AppendL( TColumn( EMdEObjectFlagStartUpNotPresent ) ); // start up not present flag
    var.AppendL( TColumn( aMediaId ) );

	__LOGQUERY_16( _L("RemoveFilesNotPresentL:"), clauseBuffer.ConstBufferL(), var);
    connection.ExecuteL( clauseBuffer.ConstBufferL(), var );

	CleanupStack::PopAndDestroy( 2, &commonClauseOne ); // var, commonClauseOne
	}

void CMdSSqlObjectManipulate::GetSchemaVersionL(
		TInt& aMajorVersion, TInt& aMinorVersion)
	{
	TInt64 minorVersion;
	TInt rowCount = MMdsPreferences::GetL( KMdsSchemaVersionName, 
			MMdsPreferences::EPreferenceBothGet, 
			aMajorVersion, &minorVersion );

	aMinorVersion = minorVersion;

	// if no rows found leave
	if( rowCount <= 0 )
		{
		User::Leave( KErrNotFound );
		}
	}

void CMdSSqlObjectManipulate::SetObjectToPresentByGuidL( 
		const TInt64& aGuidHigh, const TInt64& aGuidLow )
	{
	// get object ID for later queries
	_LIT( KGetObjectIdByGuid, "SELECT ObjectId FROM Object%u WHERE Flags&? AND GuidHigh=? AND GuidLow=?;" );

	RClauseBuffer commonClauseOne(*this, 
			KGetObjectIdByGuid.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseBuffer = commonClauseOne.BufferL();
	clauseBuffer.BufferL().Format( KGetObjectIdByGuid, KDefaultNamespaceDefId );

    RRowData var;
    CleanupClosePushL( var );
    var.ReserveL( 3 ); // for flags and GUID high/low in WHERE

    var.AppendL( TColumn( (TUint32)EMdEObjectFlagNotPresent ) );
    var.AppendL( TColumn( aGuidHigh ) );
    var.AppendL( TColumn( aGuidLow ) );

	RMdsStatement statement;
	CleanupClosePushL( statement );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	__LOGQUERY_16( _L("SetObjectToPresentByGuidL q1:"), clauseBuffer.ConstBufferL(), var);

    connection.ExecuteQueryL( clauseBuffer.ConstBufferL(), statement, var );

	var.Free();
	var.Reset();
	TItemId objectId = KNoId;
	var.AppendL( TColumn( objectId ) );

	if( connection.NextRowL( statement, var ) )
		{
		var.Column( 0 ).Get( objectId );

		// set object, which object ID is matching, to present state
		_LIT( KSetObjectToPresentByGuid, "UPDATE Object%u SET Flags=Flags&? WHERE ObjectId=? AND (Flags&?)<>0;" );

		RClauseBuffer commonClauseTwo(*this, 
				KSetObjectToPresentByGuid.iTypeLength + KMaxUintValueLength);
		CleanupClosePushL( commonClauseTwo );
		CMdsClauseBuffer& clauseBuffer2 = commonClauseTwo.BufferL();
		clauseBuffer2.BufferL().Format( KSetObjectToPresentByGuid, 
				KDefaultNamespaceDefId );

		var.Free();
		var.Reset();
		var.AppendL( TColumn( (TUint32)~EMdEObjectFlagNotPresent ) );
		var.AppendL( TColumn( objectId ) );
		
		var.AppendL( TColumn( (TUint32)EMdEObjectFlagNotPresent ) );

		__LOGQUERY_16( _L("SetObjectToPresentByGuidL q2:"), 
				clauseBuffer2.ConstBufferL(), var);
		
		connection.ExecuteL( clauseBuffer2.ConstBufferL(), var );
		
		CleanupStack::PopAndDestroy( &commonClauseTwo );

		// set relations, which left or right object ID is matching, 
		// to present state
		_LIT( KSetRelationToPresentByGuid, "UPDATE Relations%u SET Flags=Flags&? WHERE LeftObjectId=? OR RightObjectId=?;" );
		
		RClauseBuffer commonClauseThree(*this, 
				KSetRelationToPresentByGuid.iTypeLength + KMaxUintValueLength);
		CleanupClosePushL( commonClauseThree );
		CMdsClauseBuffer& clauseBuffer3 = commonClauseThree.BufferL();
		clauseBuffer3.BufferL().Format( KSetRelationToPresentByGuid, 
				KDefaultNamespaceDefId );

		var.Free();
		var.Reset();
		var.AppendL( TColumn( (TUint32)~EMdERelationFlagNotPresent ) );
		var.AppendL( TColumn( objectId ) );
		var.AppendL( TColumn( objectId ) );

		__LOGQUERY_16( _L("SetObjectToPresentByGuidL q3:"), 
				clauseBuffer3.ConstBufferL(), var);

		connection.ExecuteL( clauseBuffer3.ConstBufferL(), var );
		
		CleanupStack::PopAndDestroy( &commonClauseThree );
		}
	// no any matching object
	else
		{
		User::Leave( KErrNotFound );
		}

	CleanupStack::PopAndDestroy( 3, &commonClauseOne ); // statement, var, commonClauseOne
	}

void CMdSSqlObjectManipulate::ChangePathL(
		const TDesC& aOldPath, const TDesC& aNewPath, 
		RArray<TItemId>& aObjectIds)
	{
	// collect object IDs from object which match to the old path
	_LIT( KGetObjectIdByBeginOfUri, "SELECT ObjectId FROM Object%u WHERE NOT Flags&? AND substr(URI, 1, ?) = ?;" );

	RClauseBuffer commonClauseOne(*this, 
			KGetObjectIdByBeginOfUri.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseBuffer = commonClauseOne.BufferL();
	clauseBuffer.BufferL().Format( KGetObjectIdByBeginOfUri, KDefaultNamespaceDefId );

	const TUint32 flags = EMdEObjectFlagNotPresent | EMdEObjectFlagRemoved | EMdEObjectFlagGarbage;

	const TInt oldPathLength = aOldPath.Length();

	RRowData var;
    CleanupClosePushL( var );
	var.ReserveL( 3 );
    var.AppendL( TColumn( flags ) );
    var.AppendL( TColumn( oldPathLength ) );
    var.AppendL( TColumn( aOldPath ) );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	RMdsStatement statement;
	CleanupClosePushL( statement );

	__LOGQUERY_16( _L("ChangePathL q1:"), clauseBuffer.ConstBufferL(), var);

    connection.ExecuteQueryL( clauseBuffer.ConstBufferL(), statement, var );

    var.Free();
    var.Reset();
    TItemId objectId( 0 );
    var.AppendL( TColumn( objectId ) );

	while( connection.NextRowL( statement, var ) )
		{
		var.Column( 0 ).Get( objectId );
		aObjectIds.AppendL( objectId );
		}

	// update the new path to objects which match with the old path
	_LIT( KChangeOldPathToNewPath, "UPDATE Object%u SET URI=? || substr(URI, ?, length(URI)) WHERE NOT Flags&? AND substr(URI, 1, ?) = ?;" );

	RClauseBuffer commonClauseTwo(*this, 
			KChangeOldPathToNewPath.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseTwo );
	CMdsClauseBuffer& clauseBuffer2 = commonClauseTwo.BufferL();
	clauseBuffer2.BufferL().Format( KChangeOldPathToNewPath, KDefaultNamespaceDefId );

	var.Free();
	var.Reset();

	var.ReserveL( 5 );
    var.AppendL( TColumn( aNewPath ) );
    var.AppendL( TColumn( oldPathLength + 1 ) );
    var.AppendL( TColumn( flags ) );
    var.AppendL( TColumn( oldPathLength ) );
    var.AppendL( TColumn( aOldPath ) );

	__LOGQUERY_16( _L("ChangePathL q2:"), clauseBuffer2.ConstBufferL(), var);

	connection.ExecuteL( clauseBuffer2.ConstBufferL(), var );

	CleanupStack::PopAndDestroy( 4, &commonClauseOne ); // commonClauseTwo, statement, var, commonClauseOne
	}

void CMdSSqlObjectManipulate::ChangeMediaIdL()
	{
	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	
	TVolumeInfo volumeInfo;
	RFs fs;
	User::LeaveIfError( fs.Connect() );
	CleanupClosePushL( fs );

	fs.Volume( volumeInfo, EDriveC );
	CleanupStack::PopAndDestroy( &fs );

	// update the new media id to objects which match with the old id
	_LIT( KChangeOldIdToNewId, "UPDATE Object%u SET MediaId=? WHERE NOT Flags&? AND MediaId = (SELECT Value FROM MdE_Preferences WHERE Key=?);" );

	RClauseBuffer clauseOne( *this, KChangeOldIdToNewId.iTypeLength + KMaxUintValueLength );
	CleanupClosePushL( clauseOne );
	CMdsClauseBuffer& clauseBuffer = clauseOne.BufferL();
	clauseBuffer.BufferL().Format( KChangeOldIdToNewId, KDefaultNamespaceDefId );

	const TUint32 flags = EMdEObjectFlagNotPresent | EMdEObjectFlagRemoved | EMdEObjectFlagGarbage;

	RRowData var;
	CleanupClosePushL( var );

	var.ReserveL( 3 );
	var.AppendL( TColumn( (TUint32) volumeInfo.iUniqueID ) );
	var.AppendL( TColumn( flags ) );
	var.AppendL( TColumn( KCMediaIdKey ) );

	__LOGQUERY_16( _L("ChangeMediaIdL q2:"), clauseBuffer.ConstBufferL(), var);

	connection.ExecuteL( clauseBuffer.ConstBufferL(), var );
	
	// update the new media id to objects which match with the old id
	_LIT( KUpdateMediaId, "UPDATE MdE_Preferences SET Value=? WHERE Key = ?;" );
	
	var.Free();
	var.Reset();
	
	TTime currentTime;
	currentTime.UniversalTime();
	const TInt64 currentTime64 = currentTime.Int64();

	var.ReserveL( 2 );
	var.AppendL( TColumn( (TUint32) volumeInfo.iUniqueID ) );
	var.AppendL( TColumn( KCMediaIdKey ) );

	connection.ExecuteL( KUpdateMediaId, var );

	CleanupStack::PopAndDestroy( &var );
	CleanupStack::PopAndDestroy( &clauseOne );
	}

void CMdSSqlObjectManipulate::CheckMassStorageMediaIdL( const TUint32 aMediaId )
    {
    TUint32 oldMediaId( 0 );
    const TInt rowCount = MMdsPreferences::GetL( KMassStorageMediaIdKey, 
                                                                 MMdsPreferences::EPreferenceValueGet, oldMediaId );
    if( rowCount == 0 )
        {
        MMdsPreferences::InsertL( KMassStorageMediaIdKey, MMdsPreferences::EPreferenceValueSet, (TUint32) aMediaId );
        }
    else if( aMediaId != oldMediaId )
        {
        RArray<TItemId> objectIds;
        CleanupClosePushL( objectIds );
        MMdsPreferences::UpdateL( KMassStorageMediaIdKey, MMdsPreferences::EPreferenceValueSet, (TUint32) aMediaId );
        SetFilesToNotPresentL( oldMediaId, EFalse, objectIds );
        CleanupStack::PopAndDestroy( &objectIds );
        RemoveFilesNotPresentL( oldMediaId, NULL );
        }
    }

const CMdsPropertyDef& CMdSSqlObjectManipulate::ReadPropertyL( 
		CMdCSerializationBuffer& aBuffer, const CMdsObjectDef& aObjectDef,
		CMdsClauseBuffer& aBaseObjectClause, CMdsClauseBuffer& aObjectClause,
		RRowData& aBaseObjectDataRow, RRowData& aObjectDataRow, TUint8& aFlags)
	{
	const TMdCProperty& property = TMdCProperty::GetFromBufferL( aBuffer );
	const CMdsPropertyDef* propertyDef = aObjectDef.GetPropertyByIdL( 
			property.iPropertyDefId );
	if ( !propertyDef )
		{
#ifdef _DEBUG
		WRITELOG( "Incorrect property" );
#endif
		User::Leave( KErrMdEUnknownPropertyDef );
		}
	aFlags = property.iModFlags;

	if (property.iModFlags == EMdEPropertyModNone)
		{
		return *propertyDef;
		}

	const TBool baseObjectProperty = 
		iBaseObjectDef->GetPropertyByIdL(property.iPropertyDefId) != NULL;

	// if property is not removed add actual value
	if( !( property.iModFlags & EMdEPropertyModRemove ) )
		{
		switch(propertyDef->GetType())
			{
			case EPropertyBool:
				{
				const TBool boolValue = property.iValue.iInt32;
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( boolValue ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( boolValue ) );
					}
				break;
				}
			case EPropertyInt8:
				{
				const TInt8 int8Value = property.iValue.iInt32;
				if ( !propertyDef->CheckMinMaxValue( (TInt32)int8Value ) )
					{
#ifdef _DEBUG
					TInt32 debugValue = int8Value;
					WRITELOG2( "Incorrect property[%S] value: %d", 
							&propertyDef->GetName(), debugValue );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( int8Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( int8Value ) );
					}
				break;
				}
			case EPropertyUint8:
				{
				const TUint8 uInt8Value = property.iValue.iUint32;
				if ( !propertyDef->CheckMinMaxValue( (TInt32)uInt8Value ) )
					{
#ifdef _DEBUG
					TInt32 debugValue = uInt8Value;
					WRITELOG2( "Incorrect property[%S] value: %d", 
							&propertyDef->GetName(), debugValue );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( uInt8Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( uInt8Value ) );
					}
				break;
				}
			case EPropertyInt16:
				{
				const TInt16 int16Value = property.iValue.iInt32;
				if ( !propertyDef->CheckMinMaxValue( (TInt32)int16Value ) )
					{
#ifdef _DEBUG
					TInt32 debugValue = int16Value;
					WRITELOG2( "Incorrect property[%S] value: %d", 
							&propertyDef->GetName(), debugValue );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( int16Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( int16Value ) );
					}
				break;
				}
			case EPropertyUint16:
				{
				const TUint16 uInt16Value = property.iValue.iUint32;
				if ( !propertyDef->CheckMinMaxValue( (TInt32)uInt16Value ) )
					{
#ifdef _DEBUG
					TInt32 debugValue = uInt16Value;
					WRITELOG2( "Incorrect property[%S] value: %d", 
							&propertyDef->GetName(), debugValue );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( uInt16Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( uInt16Value ) );
					}
				break;
				}
			case EPropertyInt32:
				{
				const TInt32 int32Value = property.iValue.iInt32;
				if ( !propertyDef->CheckMinMaxValue( int32Value ) )
					{
#ifdef _DEBUG
					WRITELOG2( "Incorrect property[%S] value: %d", 
							&propertyDef->GetName(), int32Value );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( int32Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( int32Value ) );
					}
				break;
				}
			case EPropertyUint32:
				{
				const TUint32 uInt32Value = property.iValue.iUint32;
				if ( !propertyDef->CheckMinMaxValue( uInt32Value ) )
					{
#ifdef _DEBUG
					WRITELOG2( "Incorrect property[%S] value: %u", 
							&propertyDef->GetName(), uInt32Value );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( uInt32Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( uInt32Value ) );
					}
				break;
				}
			case EPropertyInt64:
				{
				const TInt64 int64Value = property.iValue.iInt64;
				if ( !propertyDef->CheckMinMaxValue( int64Value ) )
					{
#ifdef _DEBUG
					WRITELOG2( "Incorrect property[%S] value: %Ld", 
							&propertyDef->GetName(), int64Value );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( int64Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( int64Value ) );
					}
				break;
				}
			case EPropertyTime:
				{
				const TInt64 int64Value = property.iValue.iInt64;
				if ( !propertyDef->CheckMinMaxValue( int64Value ) )
					{
#ifdef _DEBUG					
					WRITELOG2( "Incorrect property[%S] value: %Ld", 
							&propertyDef->GetName(), int64Value );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( int64Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( int64Value ) );
					}
				break;
				}
			case EPropertyReal32:
				{
				const TReal32 real32Value = property.iValue.iReal;
				if ( !propertyDef->CheckMinMaxValue( real32Value ) )
					{
#ifdef _DEBUG
					TReal64 debugValue = real32Value;
					WRITELOG2( "Incorrect property[%S] value: %.2f", 
							&propertyDef->GetName(), debugValue );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( real32Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( real32Value ) );
					}
				break;
				}
			case EPropertyReal64:
				{
				const TReal64 real64Value = property.iValue.iReal;
				if ( !propertyDef->CheckMinMaxValue( real64Value ) )
					{
#ifdef _DEBUG					
					WRITELOG2( "Incorrect property[%S] value: %.2f", 
							&propertyDef->GetName(), real64Value );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( real64Value ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( real64Value ) );
					}
				break;
				}
			case EPropertyText:
				{
				aBuffer.PositionL( property.iValue.iPtr.iOffset );
				TPtrC16 textValue( aBuffer.ReceivePtr16L() );
				if ( !propertyDef->CheckMinMaxValue( (TInt32)textValue.Length() ) )
					{
#ifdef _DEBUG
					WRITELOG3( "Incorrect property[%S] value: \"%S\", length: %d", 
							&propertyDef->GetName(), &textValue, 
							textValue.Length() );
#endif
					User::Leave( KErrMdEPropertyValueNotBetweenAllowedMinMax );
					}
				if ( baseObjectProperty )
					{
					aBaseObjectDataRow.AppendL( TColumn( textValue ) );
					}
				else
					{
					aObjectDataRow.AppendL( TColumn( textValue ) );
					}
				break;
				}
			default:
				User::Leave( KErrMdEUnknownPropertyType );
			}
		}
	// if property is removed add null value
	else
		{
		TPtrC16 val = TPtr16((TUint16*)0, 0);
		if( baseObjectProperty )
			{
			aBaseObjectDataRow.AppendL( TColumn( val ) );
			}
		else
			{
			aObjectDataRow.AppendL( TColumn( val ) );
			}
		}

	if( baseObjectProperty )
		{
		aBaseObjectClause.AppendL( KComma );
		aBaseObjectClause.AppendL( propertyDef->GetName() );
		}
	else
		{
		aObjectClause.AppendL( KComma );
		aObjectClause.AppendL( propertyDef->GetName() );
		}
	
	return *propertyDef;
	}

TItemId CMdSSqlObjectManipulate::AddObjectL( CMdSSqLiteConnection& aConnection, 
       CMdCSerializationBuffer& aBuffer,
       RMdsStatement& aMdsBaseObjStatement, RMdsStatement& aMdsObjStatement,
       const CMdSServerSession* aServerSession )
	{
	_LIT( KMdsObjectAddBaseObjectBegin, "INSERT INTO Object%u(ObjectId,ObjectDefId,Flags,MediaId,GuidHigh,GuidLow,URI" );
	_LIT( KMdsObjectAddBaseObjectMiddle, ") VALUES(?,?,?,?,?,?,?" );
	_LIT( KMdsObjectAddObjectBegin, "INSERT INTO %S%u(ObjectId" );
	_LIT( KMdsObjectAddObjectMiddle, ") VALUES(?" );
	_LIT( KMdsObjectAddObjectEnd,   ");" );

	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}

	RRowData baseObjectRow;
	CleanupClosePushL( baseObjectRow );
	RRowData objectRow;
	CleanupClosePushL( objectRow );

	const TMdCObject& object = TMdCObject::GetFromBufferL( aBuffer );
	// there must be at least one property (btw. base object have 7 properties)
	if (object.iProperties.iPtr.iCount < 1)
		{
		User::Leave( KErrMdEMandatoryPropertyMissing );
		}

	// objectid
	if (object.iId != KNoId)
		{
		User::Leave( KErrAlreadyExists );
		}

	RSQLIndex sqlIndex;
	CleanupClosePushL( sqlIndex );
	const TItemId objectId = sqlIndex.GetId();

	baseObjectRow.AppendL( TColumn( objectId ) );
	objectRow.AppendL( TColumn( objectId ) );

	// objectdefid
	const CMdsObjectDef* objectDef = iNamespaceDef->GetObjectByIdL( object.iDefId );
	if ( !objectDef )
		{
		// objectDef doesn't exist
		User::Leave( KErrMdEUnknownObjectDef );
		}
	baseObjectRow.AppendL( TColumn( object.iDefId ) );

	// get BaseObjectDef
	iBaseObjectDef = iNamespaceDef->GetObjectByIdL( KBaseObjectDefId );

	RClauseBuffer commonClauseOne(*this);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseBaseObject = commonClauseOne.BufferL(); 
	RClauseBuffer commonClauseTwo(*this);
	CleanupClosePushL( commonClauseTwo );
	CMdsClauseBuffer& clauseObject = commonClauseTwo.BufferL(); 

	const TDesC& objName = objectDef->GetName();
	if(objName != iLastAddedObjName)
	    {
        iLastAddedObjName = objName;
	    aMdsObjStatement.Close();
        aMdsObjStatement = RMdsStatement();
        }
 
    clauseObject.BufferL().Format( KMdsObjectAddObjectBegin, &objName, iNamespaceDef->GetId() );
	clauseBaseObject.BufferL().Format( KMdsObjectAddBaseObjectBegin, iNamespaceDef->GetId() );

	TUint32 objectFlags = 0;
	if ( !( object.iFlags & ( EMdEObjectFlagModOpen | EMdEObjectFlagAutoLock ) ) )
		{
		User::Leave( KErrMdENotLocked );
		}

	if (object.iFlags & EMdEObjectFlagConfidential) 
		{
		objectFlags |= EMdEObjectFlagConfidential;
		}
	if (object.iFlags & EMdEObjectFlagModFreeText)
		{
		objectFlags |= EMdEObjectFlagFreetexts;
		}
	if (object.iFlags & EMdEObjectFlagPlaceholder)
		{
		objectFlags |= EMdEObjectFlagPlaceholder;
		}
	if (objectDef->GetFlags() == CMdsObjectDef::EObjectDefFlagsContext)
		{
		objectFlags |= EMdEObjectFlagContext;
		}
	baseObjectRow.AppendL( TColumn( objectFlags ) );

	// mediaId
	baseObjectRow.AppendL( TColumn( object.iMediaId ) );

	TInt64 guidHigh = object.iGuidHigh;
	TInt64 guidLow = object.iGuidLow;

	if (guidLow == 0 && guidHigh == 0)
		{
		iGenerator->GenerateGuid( guidHigh, guidLow );
		}

	baseObjectRow.AppendL( TColumn( guidHigh ) );
	baseObjectRow.AppendL( TColumn( guidLow ) );

	// uri
	HBufC* uriBuf = NULL;
	if (object.iUri.iPtr.iCount == 0)
		{
		uriBuf = iGenerator->GenerateUriL( *objectDef, guidHigh, guidLow );
		}
	else
		{
		aBuffer.PositionL( object.iUri.iPtr.iOffset );
		uriBuf = aBuffer.ReceiveDes16L();
		}
	CleanupStack::PushL( uriBuf );
	TPtr16 uri( uriBuf->Des() );
	uri.LowerCase();
	baseObjectRow.AppendL( TColumn( uri ) );

	const TInt baseObjectRowSizeWithoutProperties = baseObjectRow.Size();

	TInt mandatoryPropertyCount = objectDef->GetMandatoryPropertyCount();
	
	// try to add property
	for ( TUint32 i = 0; i < object.iProperties.iPtr.iCount; ++i )
		{
		aBuffer.PositionL( object.iProperties.iPtr.iOffset + i * sizeof(TMdCProperty) );
		TUint8 modFlags;
		const CMdsPropertyDef& propertyDef = ReadPropertyL( aBuffer, *objectDef, clauseBaseObject, clauseObject, baseObjectRow, objectRow, modFlags );
		if ( modFlags == EMdEPropertyModNone )
			{
			continue;
			}

		// check if mandatory property is removed
		if( propertyDef.GetMandatory() )
			{
			if( modFlags & EMdEPropertyModRemove )
				{
				User::Leave( KErrMdEMandatoryPropertyMissing );
				}
			else
				{
				--mandatoryPropertyCount;
				}
			}
		}

	if( mandatoryPropertyCount != 0 )
		{
		User::Leave( KErrMdEMandatoryPropertyMissing );
		}

	clauseBaseObject.AppendL( KMdsObjectAddBaseObjectMiddle );

	const TInt baseObjectPropertyCount = baseObjectRow.Size() - 
		baseObjectRowSizeWithoutProperties;

	for ( TInt i = 0; i < baseObjectPropertyCount; ++i )
		{
		clauseBaseObject.AppendL( KComma );
		clauseBaseObject.AppendL( KVariable );
		}

	clauseObject.AppendL( KMdsObjectAddObjectMiddle );

	// object row property count (object row size without object ID)
	const TInt objectPropertyCount = objectRow.Size() - 1;

	for ( TInt i = 0; i < objectPropertyCount; ++i )
		{
		clauseObject.AppendL( KComma );
		clauseObject.AppendL( KVariable );
		}
	
	clauseBaseObject.AppendL( KMdsObjectAddObjectEnd );
	clauseObject.AppendL( KMdsObjectAddObjectEnd );

	// EVERYTHING IS OK - add object to DB

	TInt queryResult = 0, err;
	// add base object properties
	__LOGQUERY_16( _L("Add BaseObject to DB:"), clauseBaseObject.ConstBufferL(), baseObjectRow);
	TRAP( err, aConnection.ExecuteL( clauseBaseObject.ConstBufferL(), baseObjectRow, &aMdsBaseObjStatement ) );
	if (err == KSqlErrConstraint)
		{
		__LOG1( ELogQuery, "Adding baseObject constraint error - err:%d", err );
		TRAP_IGNORE( RemoveObjectForceL( uri, KNoId ) );
		__LOGQUERY_16( _L("Add AGAIN BaseObject to DB:"), clauseBaseObject.ConstBufferL(), baseObjectRow);
		TRAP( err, aConnection.ExecuteL( clauseBaseObject.ConstBufferL(), baseObjectRow, &aMdsBaseObjStatement ) );
		}

	if (err != KErrNone)
		{
		__LOG1( ELogQuery, "Adding baseObject failed - err:%d", err );
		User::Leave( KErrGeneral );
		}

	if( !( // skip if object definition is "base object"
		   // and object is placeholder
			(object.iDefId == KBaseObjectDefId) &&
			(object.iFlags & EMdEObjectFlagPlaceholder)
		 ) 
	  )
		{	
		__LOGQUERY_16( _L("Add Object to DB:"), clauseObject.ConstBufferL(), 
				objectRow);
		TRAP( err, queryResult = aConnection.ExecuteL( 
		        clauseObject.ConstBufferL(), objectRow, &aMdsObjStatement ) );
		if (err != KErrNone || queryResult != 1)
			{
			__LOG2( ELogQuery, "Adding object failed - err:%d, queryResult:%d", err, queryResult );
			TRAP_IGNORE( RemoveObjectForceL( objectId ) );
			User::Leave( err );
			}
		}

	CleanupStack::PopAndDestroy( uriBuf );
	CleanupStack::PopAndDestroy( 2, &commonClauseOne ); // commonClauseTwo, commonClauseOne

	// add freetext to DB
	if ( object.iFreeTexts.iPtr.iCount > 0 )
		{
		aBuffer.PositionL( object.iFreeTexts.iPtr.iOffset );
		TRAP( err, AddFreeTextL( aBuffer, object.iFreeTexts.iPtr.iCount, objectId ) );
		if (err != KErrNone)
			{
			__LOG1( ELogQuery, "Adding object freetext failed - err:%d", err );
			TRAP_IGNORE( RemoveObjectForceL( objectId ) );
			User::Leave( err );
			}
		}

	sqlIndex.Commit();
	CleanupStack::PopAndDestroy( &sqlIndex );
	CleanupStack::PopAndDestroy( 2, &baseObjectRow ); // objectRow, baseObjectRow

	if( ( object.iFlags & EMdEObjectFlagAutoLock ) && aServerSession )
		{
		iLockList.LockObjectL( *aServerSession, *iNamespaceDef, objectId );
		}
	
	return objectId;
	}

TUint32 CMdSSqlObjectManipulate::AddFreeTextToDBL( TPtrC16& aWord, TItemId aObjectId,
    TInt32 aPosition, TBool aSearch )
	{
	_LIT( KMdsFreeTextAdd, "INSERT INTO TextSearch%d(WordId,ObjectId,Position) VALUES(?,?,?)" );
	_LIT( KMdsFreeTextDictAdd, "INSERT INTO TextSearchDictionary%d(Word) VALUES(?)" );

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	RClauseBuffer commonClauseOne(*this);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& freeTextAdd     = commonClauseOne.BufferL(); 
	RClauseBuffer commonClauseTwo(*this);
	CleanupClosePushL( commonClauseTwo );
	CMdsClauseBuffer& freeTextDictAdd = commonClauseTwo.BufferL();

	freeTextAdd.BufferL().Format( KMdsFreeTextAdd, iNamespaceDef->GetId() );
	freeTextDictAdd.BufferL().Format( KMdsFreeTextDictAdd, iNamespaceDef->GetId() );

	TItemId freeTextId = KNoId;
	RRowData freeTextRow;
	CleanupClosePushL( freeTextRow );
	RRowData freeTextRowDict;
	CleanupClosePushL( freeTextRowDict );

	freeTextRow.ReserveL( 3 );

	freeTextRow.AppendL( TColumn(KNoId) );
	freeTextRow.AppendL( TColumn(aObjectId) );
	freeTextRow.AppendL( TColumn(aPosition) );

    freeTextId = FindFreeTextInDbL( aWord );
	if ( aSearch && freeTextId )
		{
		freeTextRow.Column(0).Set( freeTextId );
		__LOGQUERY_16( _L("Add FreeText index to DB:"), 
				freeTextAdd.ConstBufferL(), freeTextRow);
		connection.ExecuteL( freeTextAdd.ConstBufferL(), freeTextRow );
		}
	else
		{
		freeTextRowDict.AppendL( TColumn( aWord ) );
		__LOGQUERY_16( _L("Add FreeText to DB:"), 
				freeTextDictAdd.ConstBufferL(), freeTextRowDict);
		TRAPD( err, freeTextId = MMdSIndexer::ExecuteAndGetIndexL( 
				freeTextDictAdd.ConstBufferL(), freeTextRowDict ) );
		if (err != KErrNone || freeTextId == KNoId)
			{
			__LOG2( ELogQuery, "Adding freetextDict failed - err:%d, freeTextId:%d", 
					err, freeTextId );
			User::Leave( KErrGeneral );
			}
		
		freeTextRow.Column(0).Set( freeTextId );
		connection.ExecuteL( freeTextAdd.ConstBufferL(), freeTextRow );
		}

	CleanupStack::PopAndDestroy( 4, &commonClauseOne ); // freeTextRowDict, freeTextRow, commonClauseTwo, commonClauseOne
	return freeTextId;
	}

TInt CMdSSqlObjectManipulate::AddFreeTextL( CMdCSerializationBuffer& aBuffer, TInt aFreeTextCount, TItemId aObjectId )
	{
	TInt freeTextAdded = 0;

	for ( TUint32 i = 0; i < aFreeTextCount; ++i )
		{
		TPtrC16 freeText = aBuffer.ReceivePtr16L();
		AddFreeTextToDBL( freeText, aObjectId, i );
		++freeTextAdded;
		}
	return freeTextAdded;
	}

TItemId CMdSSqlObjectManipulate::FindFreeTextInDbL( TPtrC16 aFreeText )
	{
	_LIT( KMdsFreeTextSearch, "SELECT WordId FROM TextSearchDictionary%d WHERE Word=? LIMIT 1;" );
	
	RClauseBuffer commonClauseOne(*this, KMdsFreeTextSearch.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& freeTextSearchClause = commonClauseOne.BufferL();
	freeTextSearchClause.BufferL().Format( KMdsFreeTextSearch, iNamespaceDef->GetId() );

	TItemId freeTextId = 0;
	RRowData wordRow;
	CleanupClosePushL( wordRow );
	RRowData idRow;
	CleanupClosePushL( idRow );
	RMdsStatement query;
	CleanupClosePushL( query );
	
	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	wordRow.AppendL( TColumn( aFreeText ) );
	idRow.AppendL( TColumn( freeTextId ) );
	connection.ExecuteQueryL( freeTextSearchClause.ConstBufferL(), query, wordRow );
	if( connection.NextRowL( query, idRow ) )
		{
		idRow.Column( 0 ).Get( freeTextId );
		}

	CleanupStack::PopAndDestroy( 4, &commonClauseOne ); // query, idRow, wordRow, commonClauseOne
	return freeTextId;
	}

void CMdSSqlObjectManipulate::RemoveObjectForceL( const TDesC16& aUri, TItemId aObjectId )
	{
	_LIT( KMdsRemoveObjectByUri, "DELETE FROM Object%u WHERE Flags&? AND ObjectId!=? AND URI=?;" );

	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}

	RClauseBuffer commonClauseOne(*this, KMdsRemoveObjectByUri.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& removeObjectClause = commonClauseOne.BufferL();

	removeObjectClause.BufferL().Format( KMdsRemoveObjectByUri, 
			iNamespaceDef->GetId() );

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

    // do remove
    RRowData varRemove;
    CleanupClosePushL( varRemove );
    varRemove.ReserveL( 3 );
    varRemove.AppendL( TColumn( EMdEObjectFlagRemoved ) );
    varRemove.AppendL( TColumn( aObjectId ) );
    varRemove.AppendL( TColumn( aUri ) );

#ifdef _DEBUG    
#ifdef LOG_MASTER_FLAG
	TInt queryResult = 0; // For debug
	__LOGQUERY_16( _L("Remove FORCE object using URI:"), 
			removeObjectClause.ConstBufferL(), varRemove);
	TRAPD( err, queryResult = connection.ExecuteL( 
			removeObjectClause.ConstBufferL(), varRemove ) );
	if( err != KErrNone )
		{
		__LOG2( ELogQuery, "Remove FORCE object err:%d, queryResult:%d", err, queryResult );
		}
#else
    TRAP_IGNORE( connection.ExecuteL( removeObjectClause.ConstBufferL(), varRemove ) );
#endif // LOG_MASTER_FLAG
#else
    TRAP_IGNORE( connection.ExecuteL( removeObjectClause.ConstBufferL(), varRemove ) );    
#endif // _DEBUG
	
	CleanupStack::PopAndDestroy( 2, &commonClauseOne ); // varRemove, commonClauseOne
	}

// USE WITH CAUTION !!!
// THIS FUNCTION REMOVES OBJECT WITHOUT ANY CHECKING
// ONLY FOR INTERNAL USE !!!
void CMdSSqlObjectManipulate::RemoveObjectForceL( TItemId aObjectId )
	{
	_LIT( KMdsRemoveObjectById, "DELETE FROM Object%u WHERE ObjectId=?;" );

	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}

	RClauseBuffer commonClauseOne(*this,  KMdsRemoveObjectById.iTypeLength + KMaxUintValueLength );
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& removeObjectClause = commonClauseOne.BufferL();

	removeObjectClause.BufferL().Format( KMdsRemoveObjectById, iNamespaceDef->GetId() );

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

    // do remove
    RRowData varRemove;
    CleanupClosePushL( varRemove );
    varRemove.AppendL( TColumn( aObjectId ) );

#ifdef _DEBUG    
#ifdef LOG_MASTER_FLAG
	TInt queryResult = 0; // For debug
	__LOGQUERY_16( _L("Remove object using ID:"), 
			removeObjectClause.ConstBufferL(), varRemove);
	TRAPD( err, queryResult = connection.ExecuteL( 
			removeObjectClause.ConstBufferL(), varRemove ) );
	if ( err != KErrNone )
		{
		__LOG2( ELogQuery, "Remove FORCE Object err:%d, queryResult:%d", err, queryResult );
		}
#else
    TRAP_IGNORE( connection.ExecuteL( removeObjectClause.ConstBufferL(), varRemove ) );
#endif // LOG_MASTER_FLAG
#else
    TRAP_IGNORE( connection.ExecuteL( removeObjectClause.ConstBufferL(), varRemove ) );  
#endif // _DEBUG
    
	CleanupStack::PopAndDestroy( 2, &commonClauseOne ); // varRemove, commonClauseOne
	}

CMdCSerializationBuffer* CMdSSqlObjectManipulate::CheckObjectL( TInt aResultBufferSize, 
		const TDesC& aUri, TDefId aNamespaceDefId )
	{
	_LIT( KMdsCheckObjectByUri, "SELECT ObjectId, ObjectDefId, Flags FROM Object%u WHERE URI=?;" );

	RClauseBuffer commonClauseOne(*this, KMdsCheckObjectByUri.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& checkObjectClause = commonClauseOne.BufferL();

	checkObjectClause.BufferL().Format( KMdsCheckObjectByUri, aNamespaceDefId );

    RRowData rowData;
    CleanupClosePushL( rowData );
    rowData.AppendL( TColumn( aUri ) );
    
    RMdsStatement query;
	CleanupClosePushL( query );

	CMdSSqLiteConnection& db = MMdSDbConnectionPool::GetDefaultDBL();

	db.ExecuteQueryL( checkObjectClause.ConstBufferL(), query, rowData );

	rowData.Free();	
	rowData.Reset();
	rowData.ReserveL( 3 ); // space for SELECTs

	TMdCObject object;
    rowData.AppendL( TColumn( object.iId ) );
    rowData.AppendL( TColumn( object.iDefId ) );
    rowData.AppendL( TColumn( object.iFlags ) );

    CMdCSerializationBuffer* buffer = NULL;
	if ( db.NextRowL( query, rowData ) )
		{
		rowData.Column(0).Get( object.iId );
		rowData.Column(1).Get( object.iDefId );
		rowData.Column(2).Get( object.iFlags );

		buffer = CMdCSerializationBuffer::NewLC( aResultBufferSize );
		object.SerializeL( *buffer );
		CleanupStack::Pop( buffer );
		}
	else
		{
		User::Leave( KErrNotFound );
		}

	CleanupStack::PopAndDestroy( 3, &commonClauseOne ); // query, rowData, commonClauseOne

	return buffer;
	}

CMdCSerializationBuffer* CMdSSqlObjectManipulate::CheckObjectL( TInt aResultBufferSize, 
		TItemId aId, TDefId aNamespaceDefId )
	{
	_LIT( KMdsCheckObjectById, "SELECT ObjectDefId, Flags FROM Object%u WHERE ObjectId=?;" );

	RClauseBuffer commonClauseOne(*this, KMdsCheckObjectById.iTypeLength + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& checkObjectClause = commonClauseOne.BufferL();

	checkObjectClause.BufferL().Format( KMdsCheckObjectById, aNamespaceDefId );
	
    RRowData rowData;
    CleanupClosePushL( rowData );
    rowData.AppendL( TColumn( aId ) );

    RMdsStatement query;
	CleanupClosePushL( query );

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	connection.ExecuteQueryL( checkObjectClause.ConstBufferL(), query, rowData );

	rowData.Free();	rowData.Reset();
	rowData.ReserveL( 2 ); // space for SELECTs

	TMdCObject object;
	object.iId = aId;
    rowData.AppendL( TColumn( object.iDefId ) );
    rowData.AppendL( TColumn( object.iFlags ) );

    CMdCSerializationBuffer* buffer = NULL;
	if ( connection.NextRowL( query, rowData ) )
		{
		rowData.Column(0).Get( object.iDefId );
		rowData.Column(1).Get( object.iFlags );

		buffer = CMdCSerializationBuffer::NewLC( aResultBufferSize );
		object.SerializeL( *buffer );
		CleanupStack::Pop( buffer );
		}
	else
		{
		User::Leave( KErrNotFound );
		}

	CleanupStack::PopAndDestroy( 3, &commonClauseOne ); // query, rowData, commonClauseOne

	return buffer;
	}

CMdCSerializationBuffer* CMdSSqlObjectManipulate::CheckObjectL( TInt aResultBufferSize, 
		CMdCSerializationBuffer& aIds, TDefId aNamespaceDefId )
	{

	aIds.PositionL( KNoOffset );
	TUint32 idCount = 0;
	aIds.ReceiveL( idCount );

	// if no IDs, just return 0 objects
	if( idCount == 0 )
		{
		CMdCSerializationBuffer* buffer = 
			CMdCSerializationBuffer::NewLC( CMdCSerializationBuffer::KRequiredSizeForTUint32 );
		buffer->InsertL( idCount );
		return buffer;
		}

	_LIT( KMdsCheckObjectByIds, "SELECT ObjectId, ObjectDefId, Flags FROM Object%u WHERE ObjectId IN(?" );
	_LIT( KMdsCheckObjectByIdsAppend, ",?" );
	_LIT( KMdsCheckObjectByIdsEnd, ");" );

	RClauseBuffer commonClauseOne(*this, KMdsCheckObjectByIds.iTypeLength + KMaxUintValueLength + 
										 KMdsCheckObjectByIdsAppend.iTypeLength * (idCount - 1) + 
										 KMdsCheckObjectByIdsEnd.iTypeLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& checkObjectClause = commonClauseOne.BufferL();
	
	RRowData rowData;
	CleanupClosePushL( rowData );

	checkObjectClause.BufferL().Format( KMdsCheckObjectByIds, aNamespaceDefId );
	TItemId id;
	aIds.ReceiveL( id );
	rowData.AppendL( TColumn( id ) );
	
	for( TUint32 i = 1; i < idCount; i++ )
		{
		checkObjectClause.BufferL().Append( KMdsCheckObjectByIdsAppend );
		aIds.ReceiveL( id );
		rowData.AppendL( TColumn( id ) );
		}

	checkObjectClause.BufferL().Append( KMdsCheckObjectByIdsEnd );

	RMdsStatement query;
	CleanupClosePushL( query );

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	connection.ExecuteQueryL( checkObjectClause.ConstBufferL(), query, rowData );

	CMdCSerializationBuffer* buffer = CMdCSerializationBuffer::NewLC( aResultBufferSize );
	
	// initialize with 0 objects (will be updated later)
	TUint32 resultObjectCount = 0;
	buffer->InsertL( resultObjectCount );

	rowData.Free();
	rowData.Reset();

	rowData.ReserveL( 3 ); // space for SELECT's object
	
	TMdCObject object;
	rowData.AppendL( TColumn( object.iId ) );
	rowData.AppendL( TColumn( object.iDefId ) );
	rowData.AppendL( TColumn( object.iFlags ) );

	while( connection.NextRowL( query, rowData ) )
		{
		rowData.Column(0).Get( object.iId );
		rowData.Column(1).Get( object.iDefId );
		rowData.Column(2).Get( object.iFlags );

		object.SerializeL( *buffer );
		++resultObjectCount;
		}

	// update object count
	buffer->PositionL( KNoOffset );
	buffer->InsertL( resultObjectCount );

	CleanupStack::Pop( buffer );
	CleanupStack::PopAndDestroy( 3, &commonClauseOne ); // query, rowData, commonClauseOne
	
	return buffer;
	}

static TInt CompareTItemIds( const TItemId& aLeft, const TItemId& aRight )
	{
	return aLeft - aRight;
	}

void CMdSSqlObjectManipulate::CollectRemovedItemsL( RArray<TItemId>& aRemoveIds, RArray<TItemId>& aObjectIds,
                                                    RArray<TItemId>& aRelationIds, RArray<TItemId>& /*aEventIds*/ )
	{
    _LIT( KCollectGetDeleteId1, "SELECT O.ObjectId, R.RelationId FROM Object%u AS O LEFT JOIN Relations%u AS R ON O.ObjectId=R.LeftObjectId WHERE NOT O.Flags&? AND ObjectId IN(?");
    _LIT( KCollectGetDeleteId2, " UNION SELECT O.ObjectId, R.RelationId FROM Object%u AS O LEFT JOIN Relations%u AS R ON O.ObjectId=R.RightObjectId WHERE NOT O.Flags&? AND ObjectId IN(?");

	_LIT( KCollectUpdateObjectBegin,    "UPDATE Object%u SET Flags=Flags|? WHERE ObjectId IN(?" );
	_LIT( KCollectUpdateRelationsBegin, "UPDATE Relations%u SET Flags=Flags|? WHERE RelationId IN(?" );
	_LIT( KCollectMiddle, ",?" );
	_LIT( KCollectEnd1,    ")" );
	_LIT( KCollectEnd2,    ");" );

	const TInt removeIdsCount = aRemoveIds.Count();
	if (removeIdsCount < 1)
		{
		return;
		}

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	
	const TInt clauseSize( KCollectGetDeleteId1().Length() + 2*KMaxUintValueLength +
                                      (removeIdsCount-1) * KCollectMiddle().Length() +
                                      KCollectEnd1().Length() +
                                      KCollectGetDeleteId2().Length() + KMaxUintValueLength +
                                      (removeIdsCount-1) * KCollectMiddle().Length() +
                                      KCollectEnd2().Length() );
	
	HBufC* clause = HBufC::NewLC( clauseSize );
	
	TPtr clauseBuffer( clause->Des() );
	clauseBuffer.Append( KCollectGetDeleteId1 );	
	for( TInt i = removeIdsCount - 2; i >=0; i-- )
        {
	    clauseBuffer.Append( KCollectMiddle );
        }
	clauseBuffer.Append( KCollectEnd1 );	
    
	clauseBuffer.Append( KCollectGetDeleteId2 );
    for( TInt i = removeIdsCount - 2; i >=0; i-- )
        {
        clauseBuffer.Append( KCollectMiddle );
        }
    clauseBuffer.Append( KCollectEnd2 );  
	
    RClauseBuffer commonClauseOne(*this,  clauseSize );
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& buffer = commonClauseOne.BufferL();

	// getting removed object id and relation id
	buffer.BufferL().Format( clauseBuffer, 
	                                    iNamespaceDef->GetId(), 
	                                    iNamespaceDef->GetId(),
	                                    iNamespaceDef->GetId(), 
	                                    iNamespaceDef->GetId() );

	RRowData dataRow;
	CleanupClosePushL( dataRow );
	dataRow.ReserveL( removeIdsCount*2 + 2 );
	dataRow.AppendL( TColumn( EMdEObjectFlagRemoved ) );
	
    for( TInt i = removeIdsCount - 1; i >=0; i-- )
        {
        dataRow.AppendL( TColumn( aRemoveIds[i] ) );
        }

    dataRow.AppendL( TColumn( EMdEObjectFlagRemoved ) );
    
    for( TInt i = removeIdsCount - 1; i >=0; i-- )
        {
        dataRow.AppendL( TColumn( aRemoveIds[i] ) );
        }

	RMdsStatement objectQuery;
	CleanupClosePushL( objectQuery );

	__LOGQUERY_16( _L("Find objects to delete:"), buffer.ConstBufferL(), dataRow);
	connection.ExecuteQueryL( buffer.ConstBufferL(), objectQuery, dataRow );

	dataRow.Free();	
	dataRow.Reset();
	TItemId objectId = KNoId;
    TItemId prevId = objectId;
    TItemId relationId = KNoId;
	dataRow.AppendL( TColumn( objectId ) );
	dataRow.AppendL( TColumn( relationId ) );
	while ( connection.NextRowL( objectQuery, dataRow ) )
		{
		dataRow.Column(0).Get( objectId );
		if (objectId != prevId)
			{
			aObjectIds.AppendL( objectId );
			prevId = objectId;
			}
		if (!dataRow.Column(1).IsNull())
			{
			dataRow.Column(1).Get( relationId );
			const TInt error( aRelationIds.InsertInOrder( relationId, TLinearOrder<TItemId>( CompareTItemIds ) ) );
			if( error == KErrNoMemory )
			    {
			    User::Leave( error );
			    }
			}
		else
			{
			dataRow.Column(1).Set( relationId );
			}
		}

	// mark object's as removed
	// remove only item that are OK to remove (not removed earlier)
	const TInt removeObjectCount = aObjectIds.Count();
	if ( removeObjectCount > 0 )
		{
		buffer.ReserveSpaceL( KCollectUpdateObjectBegin().Length() + KMaxUintValueLength +
							   (removeObjectCount-1) * KCollectMiddle().Length() +
							   KCollectEnd2().Length() );

		buffer.BufferL().Format( KCollectUpdateObjectBegin, iNamespaceDef->GetId() );

		dataRow.Free();
		dataRow.Reset();
		dataRow.AppendL( TColumn( EMdEObjectFlagRemoved ) );

		for (TInt i = 0; i < removeObjectCount; ++i)
			{
			if(i>0)
				{
				buffer.AppendL( KCollectMiddle );
				}
			dataRow.AppendL( TColumn( aObjectIds[i] ) );
			}
		buffer.AppendL( KCollectEnd2 );

		__LOGQUERY_16( _L("Remove objects:"), buffer.ConstBufferL(), dataRow);
		connection.ExecuteL( buffer.ConstBufferL(), dataRow );
		}

	// mark relations as removed
	// remove only item that are OK to remove (not removed earlier)
	const TInt removeRelationCount = aRelationIds.Count();
	if ( removeRelationCount > 0 )
		{
		buffer.ReserveSpaceL( KCollectUpdateRelationsBegin().Length() + KMaxUintValueLength +
							   (removeRelationCount-1) * KCollectMiddle().Length() +
							   KCollectEnd2().Length() );

		buffer.BufferL().Format( KCollectUpdateRelationsBegin, iNamespaceDef->GetId() );

		dataRow.Free();	dataRow.Reset();
		dataRow.ReserveL( 1 + removeRelationCount );
		dataRow.AppendL( TColumn( EMdERelationFlagDeleted ) );

		for ( TInt i = 0; i < removeRelationCount; ++i )
			{
			if( i > 0 )
				{
				buffer.AppendL( KCollectMiddle );
				}
			dataRow.AppendL( TColumn( aRelationIds[i] ) );
			}
		buffer.AppendL( KCollectEnd2 );

		__LOGQUERY_16( _L("Remove relations:"), buffer.ConstBufferL(), dataRow);
		connection.ExecuteL( buffer.ConstBufferL(), dataRow );
		}


	CleanupStack::PopAndDestroy( 4, clause ); // objectQuery, dataRow, commonClauseOne, clause
	}

void CMdSSqlObjectManipulate::RemoveObjectsByIdL( 
		CMdCSerializationBuffer& aBuffer, TInt aCount, RArray<TItemId>& aIdArray, 
		RArray<TItemId>& aRelationIds, RArray<TItemId>& aEventIds,
		TBool aUrisRequired, RPointerArray<HBufC>& aRemovedItemUriArray )
	{
	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}

	RArray<TItemId> objectIds;
	CleanupClosePushL( objectIds );

	TItemId objectId = KNoId;

	objectIds.ReserveL( aCount );
	for (TUint32 i = 0; i < aCount; ++i)
		{
		aBuffer.ReceiveL( objectId );
		if ( objectId != KNoId && 
		     objectId != KSystemFavouritesAlbumId && 
		     objectId != KSystemCapturedAlbumId )
			{
			if ( iLockList.IsLocked( *iNamespaceDef, objectId ) )
				{
				iLockList.UnlockById( *iNamespaceDef, objectId );
				}

			objectIds.AppendL( objectId );
			}
		}
    
    CollectRemovedItemsL( objectIds, aIdArray, aRelationIds, aEventIds );

    if( aUrisRequired )
         {
         const TInt count( aIdArray.Count() );
         for( TInt i( 0 ); i < count; i++ )
             {
             TUint32 flags;
             SearchObjectUriByIdL( aIdArray[i], flags );
             aRemovedItemUriArray.AppendL( iUri );
             iUri = NULL;
             }
         }
    
    CleanupStack::PopAndDestroy( &objectIds );
	}

void CMdSSqlObjectManipulate::RemoveObjectsByUriL( 
		CMdCSerializationBuffer& aBuffer, TInt aCount, RArray<TItemId>& aIdArray,
        RArray<TItemId>& aRelationIds, RArray<TItemId>& aEventIds, 
        TBool aUrisRequired, RPointerArray<HBufC>& aRemovedItemUriArray )
	{
	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}

	RArray<TItemId> objectIds;
	CleanupClosePushL( objectIds );

	TUint32 flags;
	TItemId objectId = KNoId;
	objectIds.ReserveL( aCount );
	for (TUint32 i = 0; i < aCount; ++i)
		{
		TPtrC16 uri = aBuffer.ReceivePtr16L();
        objectId = SearchObjectByUriL( uri, flags );
        if ( objectId != KNoId && 
             objectId != KSystemFavouritesAlbumId && 
             objectId != KSystemCapturedAlbumId )
			{
			// unlock object, so update is no possible anymore
			if ( iLockList.IsLocked( *iNamespaceDef, objectId ) )
				{
				iLockList.UnlockById( *iNamespaceDef, objectId );
				}
			
			objectIds.AppendL( objectId );
			
			if( aUrisRequired )
			    {
			    // Only objects have uris, so if the are removed by uri, it can be assumed
			    // that only objects are removed.
			    aRemovedItemUriArray.AppendL( uri.AllocL() );
			    }
			}
		}

	CollectRemovedItemsL( objectIds, aIdArray, aRelationIds, aEventIds );

    CleanupStack::PopAndDestroy( &objectIds );
	}

TItemId CMdSSqlObjectManipulate::SearchObjectByUriL( const TDesC16& aUri, 
		TUint32& aFlags )
	{
	_LIT( KMdsSearchObjectbyUri, "SELECT ObjectId,Flags FROM Object%u WHERE NOT Flags&? AND NOT Flags&? AND URI=? LIMIT 1;" );

	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}

	RClauseBuffer commonClauseOne(*this, KMdsSearchObjectbyUri.iTypeLength + KMaxUintValueLength );
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& searchUriClause = commonClauseOne.BufferL();

	searchUriClause.BufferL().Format( KMdsSearchObjectbyUri, iNamespaceDef->GetId() );

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	TItemId objectId = KNoId;
	aFlags = 0;

    RRowData varSearch;
    CleanupClosePushL( varSearch );
    varSearch.ReserveL( 3 );
    varSearch.AppendL( TColumn( EMdEObjectFlagNotPresent ) );
    varSearch.AppendL( TColumn( EMdEObjectFlagRemoved ) );
    varSearch.AppendL( TColumn( aUri ) );

	RMdsStatement getQuery;
    CleanupClosePushL( getQuery );

	__LOGQUERY_16( _L("Search object by URI:"), 
			searchUriClause.ConstBufferL(), varSearch);
	TRAPD( err, connection.ExecuteQueryL( 
			searchUriClause.ConstBufferL(), getQuery, varSearch ) );

	varSearch.Free();
	varSearch.Reset();
	varSearch.AppendL( TColumn( objectId ) );
	varSearch.AppendL( TColumn( aFlags ) );
	if ( err == KErrNone && connection.NextRowL( getQuery, varSearch ) )
		{
		varSearch.Column(0).Get( objectId );
		varSearch.Column(1).Get( aFlags );
		}

	CleanupStack::PopAndDestroy( 2, &varSearch ); // getQuery, varSearch
	CleanupStack::PopAndDestroy( &commonClauseOne );
	return objectId;
	}

HBufC*& CMdSSqlObjectManipulate::SearchObjectUriByIdL( const TItemId aId, 
        TUint32& aFlags )
    {
    _LIT( KMdsSearchObjectUribyId, "SELECT URI,Flags FROM Object%u WHERE NOT Flags&? AND ObjectId=? LIMIT 1;" );

    if ( !iNamespaceDef )
        {
        User::Leave( KErrMdEUnknownNamespaceDef );
        }

    RClauseBuffer commonClauseOne(*this, KMdsSearchObjectUribyId.iTypeLength + KMaxUintValueLength );
    CleanupClosePushL( commonClauseOne );
    CMdsClauseBuffer& searchUriClause = commonClauseOne.BufferL();

    searchUriClause.BufferL().Format( KMdsSearchObjectUribyId, iNamespaceDef->GetId() );

    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

    TPtrC16 uri;
    aFlags = 0;

    RRowData varSearch;
    CleanupClosePushL( varSearch );
    varSearch.ReserveL( 2 );
    varSearch.AppendL( TColumn( EMdEObjectFlagNotPresent ) );
    varSearch.AppendL( TColumn( aId ) );

    RMdsStatement getQuery;
    CleanupClosePushL( getQuery );

    __LOGQUERY_16( _L("Search object URI by ID:"), 
            searchUriClause.ConstBufferL(), varSearch);
    TRAPD( err, connection.ExecuteQueryL( 
            searchUriClause.ConstBufferL(), getQuery, varSearch ) );

    varSearch.Free();
    varSearch.Reset();
    varSearch.AppendL( TColumn( uri ) );
    varSearch.AppendL( TColumn( aFlags ) );
    if ( err == KErrNone && connection.NextRowL( getQuery, varSearch ) )
        {
        varSearch.Column(0).Get( uri );
        varSearch.Column(1).Get( aFlags );
        iUri = uri.AllocL();
        }

    CleanupStack::PopAndDestroy( 2, &varSearch ); // getQuery, varSearch
    CleanupStack::PopAndDestroy( &commonClauseOne );
    
    return iUri;
    }

TItemId CMdSSqlObjectManipulate::UpdateObjectL( 
		CMdSSqLiteConnection& aConnection, CMdCSerializationBuffer& aBuffer )
	{
	_LIT( KMdsObjectUpdateBaseObjectBegin,     "UPDATE Object%u SET " );
	_LIT( KMdsObjectUpdateBaseObjectFlags,     "Flags=? " );
	_LIT( KMdsObjectUpdateBaseObjectEnd,       ",MediaId=?,GuidHigh=?,GuidLow=?,URI=? ");
	_LIT( KMdsObjectUpdateObjectBegin,         "UPDATE %S%u SET " );
	_LIT( KMdsObjectUpdateEnd,                 " WHERE ObjectId=?;" );
	_LIT( KUpdateEqual, "=?" );

	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}

	const TMdCObject& object = TMdCObject::GetFromBufferL( aBuffer );

	// objectid
	if (object.iId == KNoId)
		{
		User::Leave( KErrArgument );
		}

	// object must be locked
	if (!iLockList.IsLocked(*iNamespaceDef, object.iId))
		{
		User::Leave( KErrMdENotLocked );
		}

	// objectdefid
	// objectDef exists ??
	const CMdsObjectDef* objectDef = iNamespaceDef->GetObjectByIdL( 
			object.iDefId );
	if ( !objectDef )
		{
		User::Leave( KErrMdEUnknownObjectDef );
		}

	// get BaseObjectDef
	iBaseObjectDef = iNamespaceDef->GetObjectByIdL( KBaseObjectDefId );

	TUint32 objectFlags = 0;
	if (object.iFlags & EMdEObjectFlagConfidential)
		{
		objectFlags |= EMdEObjectFlagConfidential;
		}
	if (object.iFlags & EMdEObjectFlagModFreeText)
		{
		objectFlags |= EMdEObjectFlagFreetexts;
		}
	if (object.iFlags & EMdEObjectFlagPlaceholder)
		{
		objectFlags |= EMdEObjectFlagPlaceholder;
		}
	if (objectDef->GetFlags() == CMdsObjectDef::EObjectDefFlagsContext)
		{
		objectFlags |= EMdEObjectFlagContext;
		}

	if (!(object.iFlags & EMdEObjectFlagModOpen))
		{
		User::Leave( KErrMdENotLocked );
		}

	const TBool KUpdateModObject   = 
		object.iFlags & EMdEObjectFlagModObject   ? ETrue : EFalse;
	const TBool KUpdateModFreeText = 
		object.iFlags & EMdEObjectFlagModFreeText ? ETrue : EFalse;
	const TBool KUpdateModProperty = 
		object.iFlags & EMdEObjectFlagModProperty ? ETrue : EFalse;

	if ( !( KUpdateModObject || KUpdateModFreeText || KUpdateModProperty ) )
		{
		// nothing to change, so unlock object and return
		iLockList.UnlockById( *iNamespaceDef, object.iId );
		return object.iId;
		}

	RRowData baseObjectRow;
	CleanupClosePushL( baseObjectRow );
	RRowData objectRow;
	CleanupClosePushL( objectRow );

	RClauseBuffer commonClauseOne(*this);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& clauseObject = commonClauseOne.BufferL();
	
	if (KUpdateModProperty)
		{
		clauseObject.BufferL().Format( KMdsObjectUpdateObjectBegin, 
				&objectDef->GetName(), iNamespaceDef->GetId() );
		}

	RClauseBuffer commonClauseTwo(*this);
	CleanupClosePushL( commonClauseTwo );
	CMdsClauseBuffer& clauseBaseObject = commonClauseTwo.BufferL();
	if (KUpdateModObject || KUpdateModProperty)
		{
		clauseBaseObject.BufferL().Format( KMdsObjectUpdateBaseObjectBegin, 
				iNamespaceDef->GetId() );
		}

	aBuffer.PositionL( object.iUri.iPtr.iOffset );
	HBufC* uriBuf = aBuffer.ReceiveDes16L();
	CleanupStack::PushL( uriBuf );
	TPtr16 uri( uriBuf->Des() );
	uri.LowerCase();

	// if auto locking, skip extra checks, because only flags can be changed
	if( !(object.iFlags & EMdEObjectFlagAutoLock) )
		{
		// leave if GUID high and low are 0
		if( object.iGuidHigh == 0 && object.iGuidLow == 0 )
			{
			User::Leave( KErrCorrupt );
			}

		// leave if URI is "empty"
		if( uri.Length() == 0 )
			{
			User::Leave( KErrCorrupt );
			}
		}

	TBool KBaseObjectPropertyMod = EFalse;
	TBool KObjectPropertyMod     = EFalse;

	if (KUpdateModObject)
		{
		clauseBaseObject.AppendL( KMdsObjectUpdateBaseObjectFlags );
		baseObjectRow.AppendL( TColumn( objectFlags ) );

		if( !(object.iFlags & EMdEObjectFlagAutoLock) )
			{
			clauseBaseObject.AppendL( KMdsObjectUpdateBaseObjectEnd );
			baseObjectRow.AppendL( TColumn( object.iMediaId ) );
			baseObjectRow.AppendL( TColumn( object.iGuidHigh ) );
			baseObjectRow.AppendL( TColumn( object.iGuidLow ) );
			baseObjectRow.AppendL( TColumn( uri ) );
			}
		KBaseObjectPropertyMod = ETrue;
		}

	// read properties array
	if ( KUpdateModProperty )
		{
		// try to add property and increase property count
		for ( TUint32 i = 0; i < object.iProperties.iPtr.iCount; ++i )
			{
			aBuffer.PositionL( object.iProperties.iPtr.iOffset + 
					i * sizeof(TMdCProperty) );
			TUint8 modFlags;
			const CMdsPropertyDef& propertyDef = ReadPropertyL( aBuffer, 
					*objectDef, clauseBaseObject, clauseObject, baseObjectRow, 
					objectRow, modFlags );
			// check if property is already in array
			if ( modFlags == EMdEPropertyModNone )
				{
				continue;
				}

			if( ( modFlags & EMdEPropertyModRemove ) && propertyDef.GetMandatory() )
				{
				User::Leave( KErrMdEMandatoryPropertyMissing );
				}

			const TDefId propertyId = propertyDef.GetId();

			if ( iBaseObjectDef->GetPropertyByIdL( propertyId ) )
				{
				if (!KBaseObjectPropertyMod)
					{
					// remove comma before first property
					clauseBaseObject.BufferL().Delete( 
							clauseBaseObject.ConstBufferL().LocateReverse( ',' ), 1 );
					KBaseObjectPropertyMod = ETrue;
					}
				clauseBaseObject.AppendL( KUpdateEqual );
				}
			else
				{
				if (!KObjectPropertyMod)
					{
					// remove comma before first property
					clauseObject.BufferL().Delete( 
							clauseObject.ConstBufferL().LocateReverse( ',' ), 1 );
					KObjectPropertyMod = ETrue;
					}
				clauseObject.AppendL( KUpdateEqual );
				}
			}
		}

	if (KUpdateModObject || KBaseObjectPropertyMod)
		{
		clauseBaseObject.AppendL( KMdsObjectUpdateEnd );
		// append confidential and deleted flags
		baseObjectRow.AppendL( TColumn( object.iId ) );
		}

	if (KObjectPropertyMod)
		{
		clauseObject.AppendL( KMdsObjectUpdateEnd );
		// append confidential and deleted flags
		objectRow.AppendL( TColumn( object.iId ) );
		}

	TInt queryResult( 0 );
	TInt err( KErrNone );

	if ( KUpdateModObject || KBaseObjectPropertyMod )
		{
		__LOGQUERY_16( _L("Update BaseObject:"), 
				clauseBaseObject.ConstBufferL(), baseObjectRow);
		TRAP( err, queryResult = aConnection.ExecuteL( 
				clauseBaseObject.ConstBufferL(), baseObjectRow ) );

		// Try to remove the object which caused the constraint error and try add the object again.
		if ( err == KSqlErrConstraint )
			{
			__LOG2( ELogQuery, "Update baseObject constraint error - err:%d, queryResult:%d", err, queryResult );
			// The reason of the constraint error is not checked due to performance hit.
			TRAP_IGNORE( RemoveObjectForceL( uri, object.iId ) );
			__LOGQUERY_16( _L("Update AGAIN BaseObject:"), 
					clauseBaseObject.ConstBufferL(), baseObjectRow);
			// Fails if the object was not marked as removed.
			TRAP( err, queryResult = aConnection.ExecuteL( 
					clauseBaseObject.ConstBufferL(), baseObjectRow ) );
			}

		if ( err != KErrNone || queryResult != 1 )
			{
			__LOG2( ELogQuery, "Update baseObject failed - err:%d, queryResult:%d", err, queryResult );
			User::Leave( KErrGeneral );
			}
		}

	if ( KObjectPropertyMod )
		{
		__LOGQUERY_16( _L("Update Object:"), clauseObject.ConstBufferL(), 
				objectRow);
		TRAP( err, queryResult = aConnection.ExecuteL( 
				clauseObject.ConstBufferL(), objectRow ) );
		if (err != KErrNone || queryResult != 1)
			{
			__LOG2( ELogQuery, "Update Object failed - err:%d, queryResult:%d", err, queryResult );
			User::Leave( KErrGeneral );
			}
		}

	if ( KUpdateModFreeText )
		{
		if ( object.iFreeTexts.iPtr.iCount > 0 )
			{
			aBuffer.PositionL( object.iFreeTexts.iPtr.iOffset );
			UpdateFreeTextL( aBuffer, object.iFreeTexts.iPtr.iCount, object.iId );
			}
		}

    CleanupStack::PopAndDestroy( uriBuf );
    CleanupStack::PopAndDestroy( &commonClauseTwo );
	CleanupStack::PopAndDestroy( &commonClauseOne );

    // objectRow, baseObjectRow
	CleanupStack::PopAndDestroy( 2, &baseObjectRow );

	iLockList.UnlockById( *iNamespaceDef, object.iId );
	return object.iId;
	}


void CMdSSqlObjectManipulate::UpdateFreeTextL( CMdCSerializationBuffer& aBuffer,
		TInt aCount, TItemId aObjectId )
	{
	_LIT( KMdSUpdateFreeTextDelete,     "DELETE FROM TextSearch%u WHERE ObjectId=?;" );
	_LIT( KMdSUpdateFreeTextDictDelete, "DELETE FROM TextSearchDictionary%u WHERE WordId NOT IN(SELECT WordId FROM TextSearch%u);" );
	_LIT( KMdSUpdateFreeTextObjectFlagSet,   "UPDATE Object%u SET Flags=Flags|? WHERE ObjectId=?;" );
	_LIT( KMdSUpdateFreeTextObjectFlagReset, "UPDATE Object%u SET Flags=Flags&? WHERE ObjectId=?;" );

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();

	RClauseBuffer commonClauseOne(*this, KMdSUpdateFreeTextDictDelete.iTypeLength + 2*KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& buffer = commonClauseOne.BufferL();
	RRowData delRow;
	CleanupClosePushL( delRow );

	delRow.AppendL( TColumn( aObjectId ) );
	buffer.BufferL().Format( KMdSUpdateFreeTextDelete, iNamespaceDef->GetId() );
	connection.ExecuteL( buffer.ConstBufferL(), delRow );

	delRow.Free(); delRow.Reset();
	buffer.BufferL().Format( KMdSUpdateFreeTextDictDelete, iNamespaceDef->GetId(), 
			iNamespaceDef->GetId() );
	connection.ExecuteL( buffer.ConstBufferL(), delRow );

	// update object flags
	delRow.Free(); delRow.Reset();
	delRow.AppendL( TColumn( EMdEObjectFlagFreetexts ) );
	delRow.AppendL( TColumn( aObjectId ) );
	if ( AddFreeTextL( aBuffer, aCount, aObjectId ) > 0 )
		{
		buffer.BufferL().Format( KMdSUpdateFreeTextObjectFlagSet, iNamespaceDef->GetId() );
		}
	else
		{
		buffer.BufferL().Format( KMdSUpdateFreeTextObjectFlagReset, iNamespaceDef->GetId() );
		delRow.Column(0).Set( ~EMdEObjectFlagFreetexts );
		}
	connection.ExecuteL( buffer.ConstBufferL(), delRow );

	CleanupStack::PopAndDestroy( 2, &commonClauseOne ); // delRow, commonClauseOne
	}

TItemId CMdSSqlObjectManipulate::AddEventL( CMdSSqLiteConnection& aConnection, 
		CMdCSerializationBuffer& aBuffer )
	{
	_LIT( KAddEvent, "INSERT INTO Event%u(EventId,ObjectId,EventDefId,Timestamp,Source,Participant) VALUES(?,?,?,?,?,?);" );

	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}
	
	RClauseBuffer commonClauseOne(*this, KAddEvent().Length() + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& sqlBuf = commonClauseOne.BufferL();
	sqlBuf.BufferL().Format( KAddEvent, iNamespaceDef->GetId() );

   	RRowData var;
    CleanupClosePushL( var );

    const TMdCEvent& event = TMdCEvent::GetFromBufferL( aBuffer );

    TItemId eventId = event.iId;
	if ( eventId != KNoId )
		{
		User::Leave( KErrArgument );
		}
	
	RSQLIndex sqlIndex;
	CleanupClosePushL( sqlIndex );
	eventId = sqlIndex.GetId();

	if ( !iNamespaceDef->GetEventByIdL( event.iDefId ) )
		{
		User::Leave( KErrMdEUnknownEventDef );
		}

    if ( event.iObjectId == KNoId )
    	{
    	User::Leave( KErrCorrupt );
    	}

    var.AppendL( TColumn( eventId ) );
    var.AppendL( TColumn( event.iObjectId ) );
    var.AppendL( TColumn( event.iDefId ) );
    var.AppendL( TColumn( event.iTime.Int64() ) );

    TPtrC16 source;
    if ( event.iSourceText.iPtr.iCount > 0 )
    	{
    	aBuffer.PositionL( event.iSourceText.iPtr.iOffset );
        source.Set( aBuffer.ReceivePtr16L() );
    	}
    else
    	{
    	source.Set( TPtr16((TUint16*)0, 0) );
    	}
    var.AppendL( TColumn( source ) );

	TPtrC16 participant;
    if ( event.iParticipantText.iPtr.iCount > 0 )
    	{
    	aBuffer.PositionL( event.iParticipantText.iPtr.iOffset );
    	participant.Set( aBuffer.ReceivePtr16L() );
    	}
    else
    	{
    	participant.Set( TPtr16((TUint16*)0, 0) );
    	}
    var.AppendL( TColumn( participant ) );

    aConnection.ExecuteL( sqlBuf.ConstBufferL(), var );

	sqlIndex.Commit();
	CleanupStack::PopAndDestroy( 3, &commonClauseOne ); // sqlIndex, var, commonClauseOne
	return eventId;
	}
        
TItemId CMdSSqlObjectManipulate::AddRelationL( 
		CMdSSqLiteConnection& aConnection, CMdCSerializationBuffer& aBuffer )
	{
	_LIT( KAddRelation, "INSERT INTO Relations%u(RelationId,Flags,RelationDefId,LeftObjectId,RightObjectId,Parameter,GuidHigh,GuidLow,LastModifiedDate) VALUES(?,?,?,?,?,?,?,?,?);" );

	if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}
	
	RClauseBuffer commonClauseOne(*this, KAddRelation().Length() + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& buffer = commonClauseOne.BufferL();
	buffer.BufferL().Format( KAddRelation, iNamespaceDef->GetId() );

    RRowData var;
	CleanupClosePushL( var );

	const TMdCRelation& relation = TMdCRelation::GetFromBufferL( aBuffer );
	TItemId relationId = relation.iId;

	if ( relationId != KNoId )
		{
		User::Leave( KErrArgument );
		}
	
	RSQLIndex sqlIndex;
	CleanupClosePushL( sqlIndex );
	relationId = sqlIndex.GetId();

	if ( !iNamespaceDef->GetRelationByIdL( relation.iDefId ) )
		{
		User::Leave( KErrMdEUnknownRelationDef );
		}

    if ( relation.iLeftObjectId == KNoId || relation.iRightObjectId == KNoId )
    	{
    	User::Leave( KErrCorrupt );
    	}

	TInt64 guidHigh = relation.iGuidHigh;
	TInt64 guidLow = relation.iGuidLow;
	if ( guidHigh == 0 && guidLow == 0 )
		{
		iGenerator->GenerateGuid( guidHigh, guidLow );
		}

	// if last modified date is 0, set it to current universal time
	TInt64 lastModifiedDate = relation.iLastModifiedDate.Int64();
	if( lastModifiedDate == 0 )
		{
		TTime currentTime;
		currentTime.UniversalTime();
		lastModifiedDate = currentTime.Int64();
		}

    var.AppendL( TColumn( relationId ) );
    var.AppendL( TColumn( TUint32(0) ) ); // no flags
    var.AppendL( TColumn( relation.iDefId) );
    var.AppendL( TColumn( relation.iLeftObjectId ) );
    var.AppendL( TColumn( relation.iRightObjectId ) );
    var.AppendL( TColumn( relation.iParameter ) );
    var.AppendL( TColumn( guidHigh ) );
    var.AppendL( TColumn( guidLow ) );
    var.AppendL( TColumn( lastModifiedDate ) );

    aConnection.ExecuteL( buffer.ConstBufferL(), var );

	sqlIndex.Commit();
	CleanupStack::PopAndDestroy( 3, &commonClauseOne ); // sqlIndex, var, commonClauseOne
	return relationId;
	}

void CMdSSqlObjectManipulate::RemoveRelationsL( CMdCSerializationBuffer& aBuffer,
		TInt aCount, RArray<TItemId>& aIdArray )
    {	
	_LIT( KRemoveRelation, "UPDATE Relations%u SET Flags=Flags|? WHERE RelationId=? AND NOT Flags&?;" );
    CMdSSqLiteConnection& db = MMdSDbConnectionPool::GetDefaultDBL();
    
	RClauseBuffer commonClauseOne(*this, KRemoveRelation().Length() + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& buf = commonClauseOne.BufferL();
    buf.BufferL().Format( KRemoveRelation, iNamespaceDef->GetId() );

	TInt queryResult = 0;
	TItemId relationId = KNoId;

    RRowData varRemove;
    CleanupClosePushL( varRemove );
    varRemove.ReserveL( 3 );
    varRemove.AppendL( TColumn( 
    		EMdERelationFlagDeleted | EMdERelationFlagGarbageDeleted ) );
    varRemove.AppendL( TColumn( relationId ) );
    varRemove.AppendL( TColumn( 
    		EMdERelationFlagDeleted | EMdERelationFlagNotPresent ) );

	for ( TUint32 i = 0; i < aCount; ++i )
		{
		aBuffer.ReceiveL( relationId );
		varRemove.Column( 1 ).Set( relationId );
		TRAPD( err, queryResult = db.ExecuteL( buf.ConstBufferL(), varRemove ) );
		if ( err == KErrNone && queryResult == 1 )
			{
			aIdArray.AppendL( relationId );
			}
		else
			{
			aIdArray.AppendL( KNoId );
			}
		}
	CleanupStack::PopAndDestroy( 2, &commonClauseOne ); // varRemove, commonClauseOne
    }

void CMdSSqlObjectManipulate::RemoveEventsL( CMdCSerializationBuffer& aBuffer, 
		TInt aCount, RArray<TItemId>& aIdArray )
    {
	_LIT( KRemoveEvent, "DELETE FROM Event%u WHERE EventId=?;" );

    CMdSSqLiteConnection& db = MMdSDbConnectionPool::GetDefaultDBL();

	RClauseBuffer commonClauseOne(*this, KRemoveEvent().Length() + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& buf = commonClauseOne.BufferL();
    buf.BufferL().Format( KRemoveEvent, iNamespaceDef->GetId() );

	TInt queryResult = 0;
	TItemId eventId = KNoId;

    RRowData varRemove;
    CleanupClosePushL( varRemove );
    varRemove.AppendL( TColumn( eventId ) );

	for ( TUint32 i = 0; i < aCount; ++i )
		{
		aBuffer.ReceiveL( eventId );
		varRemove.Column( 0 ).Set( eventId );
		TRAPD( err, queryResult = db.ExecuteL( buf.ConstBufferL(), varRemove ) );
		if ( err == KErrNone && queryResult == 1 )
			{
			aIdArray.AppendL( eventId );
			}
		else
			{
			aIdArray.AppendL( KNoId );
			}
		}
	CleanupStack::PopAndDestroy( 2, &commonClauseOne ); // varRemove, commonClauseOne
    }

TItemId CMdSSqlObjectManipulate::UpdateRelationsL(
		CMdSSqLiteConnection& aConnection, CMdCSerializationBuffer& aBuffer )
    {	
	_LIT( KUpdateRelation, "UPDATE Relations%u SET RelationDefId=?,LeftObjectId=?,RightObjectId=?,Parameter=?,GuidHigh=?,GuidLow=?,LastModifiedDate=? WHERE NOT Flags&? AND NOT Flags&? AND RelationId=?;" );

if ( !iNamespaceDef )
		{
		User::Leave( KErrMdEUnknownNamespaceDef );
		}
	
	RClauseBuffer commonClauseOne(*this, KUpdateRelation().Length() + KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& sqlBuf = commonClauseOne.BufferL();
    sqlBuf.BufferL().Format( KUpdateRelation, iNamespaceDef->GetId() );

    RRowData var;
    CleanupClosePushL( var );

    const TMdCRelation& relation = TMdCRelation::GetFromBufferL( aBuffer );

    if ( relation.iId == KNoId )
    	{
    	User::Leave( KErrArgument );
    	}

    if ( !iNamespaceDef->GetRelationByIdL( relation.iDefId ) )
		{
		User::Leave( KErrMdEUnknownRelationDef );
		}

	// leave if GUID high and low are 0
	if( relation.iGuidHigh == 0 && relation.iGuidLow == 0 )
		{
		User::Leave( KErrCorrupt );
		}

	// if last modified date is 0, set it to current universal time
	TInt64 lastModifiedDate = relation.iLastModifiedDate.Int64();
	if( lastModifiedDate == 0 )
		{
		TTime currentTime;
		currentTime.UniversalTime();
		lastModifiedDate = currentTime.Int64();
		}

    var.AppendL( TColumn( relation.iDefId ) );
    var.AppendL( TColumn( relation.iLeftObjectId ) );
    var.AppendL( TColumn( relation.iRightObjectId ) );
    var.AppendL( TColumn( relation.iParameter ) );
    var.AppendL( TColumn( relation.iGuidHigh ) );
    var.AppendL( TColumn( relation.iGuidLow ) );
    var.AppendL( TColumn( lastModifiedDate ) );
    var.AppendL( TColumn( EMdERelationFlagNotPresent ) );
    var.AppendL( TColumn( EMdERelationFlagDeleted ) );
	var.AppendL( TColumn( relation.iId ) );

	aConnection.ExecuteL( sqlBuf.ConstBufferL(), var );

	CleanupStack::PopAndDestroy( 2, &commonClauseOne ); // var, commonClauseOne

	return relation.iId;
    }

void CMdSSqlObjectManipulate::GetRemovedRelationItemsL( CMdCSerializationBuffer& aBuffer,
		const RArray<TItemId>& aRemovedRelations,
		const RArray<TItemId>& aAdditionalRemovedRelations )
	{
	_LIT( KGetRelationItemsStart, "SELECT RelationId,RelationDefId,LeftObjectId,RightObjectId FROM Relations%u WHERE Flags&? AND RelationId IN(?" );
	_LIT( KGetRelationItemsMiddle, ",?" );
	_LIT( KGetRelationItemsEnd, ");" );

	const TInt relationsCount = aRemovedRelations.Count() + aAdditionalRemovedRelations.Count();
	
	TMdCItems relationItems;
	
	relationItems.iNamespaceDefId = iNamespaceDef->GetId();
	relationItems.iRelations.iPtr.iCount = 0; // will be updated later
	relationItems.iRelations.iPtr.iOffset = sizeof( TMdCItems );

	if ( relationsCount == 0 )
		{
		relationItems.SerializeL( aBuffer );

		return;
		}
	
	RClauseBuffer commonClauseOne(*this, KGetRelationItemsStart().Length() + KMaxUintValueLength
			+ KGetRelationItemsMiddle().Length() * relationsCount 
			+ KGetRelationItemsEnd().Length() );
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& sqlBuffer = commonClauseOne.BufferL();
	sqlBuffer.BufferL().Format( KGetRelationItemsStart, iNamespaceDef->GetId() );

    RRowData var;
    CleanupClosePushL( var );
    var.ReserveL( 1 + relationsCount );
    var.AppendL( EMdERelationFlagDeleted );

    const TInt removedRelationsCount = aRemovedRelations.Count();
    for (TInt i = 0; i < removedRelationsCount-1; ++i)
    	{
    	sqlBuffer.AppendL( KGetRelationItemsMiddle );
    	var.AppendL( aRemovedRelations[i] );
    	}
    if ( removedRelationsCount )
    	{
	    var.AppendL( aRemovedRelations[removedRelationsCount-1] );
    	}

    const TInt additionalRemovedRelationsCount = aAdditionalRemovedRelations.Count();
    for (TInt i = 0; i < additionalRemovedRelationsCount-1; ++i)
    	{
    	sqlBuffer.AppendL( KGetRelationItemsMiddle );
    	var.AppendL( aAdditionalRemovedRelations[i] );
    	}
    if ( removedRelationsCount == 0 /*&& additionalRemovedRelationsCount*/ )
    	{
    	// cannot be empty
    	var.AppendL( aAdditionalRemovedRelations[additionalRemovedRelationsCount-1] );
    	}
    
    sqlBuffer.AppendL( KGetRelationItemsEnd );
    
	RMdsStatement getQuery;
    CleanupClosePushL( getQuery );

	__LOGQUERY_16( _L("CMdSSqlObjectManipulate::GetRemovedRelationItemsL:"), 
			sqlBuffer.ConstBufferL(), var);
    CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	
    connection.ExecuteQueryL( sqlBuffer.ConstBufferL(), getQuery, var );

	var.Free(); 
	var.Reset();

    var.ReserveL( 4 );
    
    TMdCRelation relation;
	var.AppendL( relation.iId );
	var.AppendL( relation.iDefId );
	var.AppendL( relation.iLeftObjectId );
	var.AppendL( relation.iRightObjectId );
	
    TUint32 resultCount = 0;
    
    // move position after items
	aBuffer.PositionL( relationItems.iRelations.iPtr.iOffset );

	while( connection.NextRowL( getQuery, var ) )
		{
		++resultCount;

		var.Column( 0 ).Get( relation.iId );
		var.Column( 1 ).Get( relation.iDefId );
		var.Column( 2 ).Get( relation.iLeftObjectId );
		var.Column( 3 ).Get( relation.iRightObjectId );

		relation.SerializeL( aBuffer );
		}

	// update relation count
	relationItems.iRelations.iPtr.iCount = resultCount;

	// move position to begin of buffer and serialize items
	aBuffer.PositionL( KNoOffset );
	relationItems.SerializeL( aBuffer );

	CleanupStack::PopAndDestroy( 3, &commonClauseOne ); // getQuery, var, commonClauseOne
	}

void CMdSSqlObjectManipulate::SetPendingL(const RArray<TItemId>& aObjectIds, 
		TBool aReset)
	{
	_LIT( KUpdatePending,   "UPDATE Object%u SET Flags=Flags%c? WHERE ObjectId IN(?" );
	_LIT( KUpdatePendingMiddle, ",?" );
	_LIT( KUpdatePendingEnd, ");" );

    CMdSSqLiteConnection& db = MMdSDbConnectionPool::GetDefaultDBL();

    const TInt objectIdsCount = aObjectIds.Count();

	RClauseBuffer commonClause(*this, KUpdatePending().Length() + KMaxUintValueLength + 
			KUpdatePendingMiddle().Length() * (objectIdsCount - 1) + 
			KUpdatePendingEnd().Length() );
	CleanupClosePushL( commonClause );
	CMdsClauseBuffer& buf = commonClause.BufferL();

	const TChar KSetUpdateFlag = '|';
	const TChar KResetUpdateFlag = '&';
	
	TChar flagUpdate = KSetUpdateFlag; // set flag
	TUint32 objectFlag = EMdeObjectFlagPending;

	if( aReset )
		{
		flagUpdate = KResetUpdateFlag; // reset flag
		objectFlag = ~objectFlag; // not pending flag
		}
	
    buf.BufferL().Format( KUpdatePending, KDefaultNamespaceDefId, (TUint)flagUpdate );

    RRowData var;
    CleanupClosePushL( var );

    var.ReserveL( 1 + objectIdsCount );
    
    var.AppendL( TColumn( objectFlag ) );

	var.AppendL( aObjectIds[0] );
    for (TInt i = 1; i < objectIdsCount; ++i)
    	{
    	buf.AppendL( KUpdatePendingMiddle );
    	var.AppendL( aObjectIds[i] );
    	}
    buf.AppendL( KUpdatePendingEnd );

    db.ExecuteL( buf.ConstBufferL(), var );

	CleanupStack::PopAndDestroy( 2, &commonClause ); // var, commonClause
	}

TInt CMdSSqlObjectManipulate::GetPendingCountL(TDefId aObjectDefId)
	{
	_LIT( KGetPendingCount,   "SELECT count(*) FROM Object%u WHERE Flags&? AND NOT Flags&?" );
	_LIT( KGetPendingCountObjectDefId, " AND ObjectDefId=?" );
	_LIT( KGetPendingCountEnd, ";" );

    CMdSSqLiteConnection& db = MMdSDbConnectionPool::GetDefaultDBL();

    TInt bufferSize = KGetPendingCount().Length() + KMaxUintValueLength + 
    		KGetPendingCountEnd().Length();
    
	if( aObjectDefId != KNoDefId )	
		{
		bufferSize += KGetPendingCountObjectDefId().Length();
		}
    
	RClauseBuffer commonClause( *this, bufferSize );
	CleanupClosePushL( commonClause );
	CMdsClauseBuffer& buf = commonClause.BufferL();
    buf.BufferL().Format( KGetPendingCount, KDefaultNamespaceDefId );
    
    TInt varReservation = 2;
    
	if( aObjectDefId != KNoDefId )	
		{
		buf.AppendL( KGetPendingCountObjectDefId );
		++varReservation;
		}

	buf.AppendL( KGetPendingCountEnd );
	
    RRowData var;
    CleanupClosePushL( var );

    var.ReserveL( varReservation );

    var.AppendL( TColumn( EMdeObjectFlagPending ) );
    var.AppendL( TColumn( EMdEObjectFlagNotPresent | EMdEObjectFlagRemoved | 
    		EMdEObjectFlagPlaceholder | EMdEObjectFlagStartUpNotPresent ) );

    if( aObjectDefId != KNoDefId )
    	{
    	var.AppendL( TColumn( aObjectDefId ) );
    	}
    
	RMdsStatement getQuery;
    CleanupClosePushL( getQuery );

	db.ExecuteQueryL( buf.ConstBufferL(), getQuery, var );

	var.Free();
	var.Reset();

	TUint32 count = 0;
	
	var.AppendL( TColumn( count ) );

	if ( db.NextRowL( getQuery, var ) )
		{
		var.Column(0).Get( count );
		}

	CleanupStack::PopAndDestroy( 2, &var ); // getQuery, varSearch
	CleanupStack::PopAndDestroy( &commonClause );
	
	return count;
	}

TInt CMdSSqlObjectManipulate::GetPendingL(TDefId aObjectDefId, 
		TInt aBufferSize, RArray<TItemId>& aObjectIds)
	{
	_LIT( KGetPending,   "SELECT ObjectId FROM Object%u WHERE Flags&? AND NOT Flags&?" );
	_LIT( KGetPendingObjectDefId, " AND ObjectDefId=?" );
	_LIT( KGetPendingEnd, " LIMIT ?;" );

    CMdSSqLiteConnection& db = MMdSDbConnectionPool::GetDefaultDBL();

    TInt bufferSize = KGetPending().Length() + KMaxUintValueLength + 
    		KGetPendingEnd().Length();

	if( aObjectDefId != KNoDefId )	
		{
		bufferSize += KGetPendingObjectDefId().Length();
		}

	RClauseBuffer commonClause( *this, bufferSize );
	CleanupClosePushL( commonClause );
	CMdsClauseBuffer& buf = commonClause.BufferL();
    buf.BufferL().Format( KGetPending, KDefaultNamespaceDefId );

    TInt varReservation = 3;

	if( aObjectDefId != KNoDefId )	
		{
		buf.AppendL( KGetPendingObjectDefId );
		++varReservation;
		}

	buf.AppendL( KGetPendingEnd );

    RRowData var;
    CleanupClosePushL( var );

    var.ReserveL( varReservation );

    var.AppendL( TColumn( EMdeObjectFlagPending ) );
    var.AppendL( TColumn( EMdEObjectFlagNotPresent | EMdEObjectFlagRemoved | 
    		EMdEObjectFlagPlaceholder | EMdEObjectFlagStartUpNotPresent ) );

    if( aObjectDefId != KNoDefId )
    	{
    	var.AppendL( TColumn( aObjectDefId ) );
    	}

    // get as much as possible to buffer and check if there is more than that
    var.AppendL( TColumn( aBufferSize + 1 ) );

	RMdsStatement getQuery;
    CleanupClosePushL( getQuery );

	db.ExecuteQueryL( buf.ConstBufferL(), getQuery, var );

	var.Free();
	var.Reset();

	TItemId objectId = 0;

	var.AppendL( TColumn( objectId ) );

	TInt extraRows = 0;

	while( db.NextRowL( getQuery, var ) )
		{
		var.Column(0).Get( objectId );
		
		if( aObjectIds.Count() < aBufferSize )
			{
			aObjectIds.Append( objectId );
			}
		else
			{
			extraRows = 1;
			break;
			}
		}

	CleanupStack::PopAndDestroy( 2, &var ); // getQuery, varSearch
	CleanupStack::PopAndDestroy( &commonClause );

	return extraRows;
	}

TBool CMdSSqlObjectManipulate::DoGarbageCollectionL()
	{
    _LIT( KDeleteObject,                 "DELETE FROM Object%u WHERE ObjectId IN (SELECT ObjectId FROM Object%u WHERE Flags&? LIMIT 100);" );
	_LIT( KUpdateDeleteObject,           "UPDATE Object%u SET Flags=Flags|? WHERE Flags&?;" );
	_LIT( KDeleteRelations,              "DELETE FROM Relations%u WHERE Flags&?;" );
	_LIT( KUpdateDeleteRelations,        "UPDATE Relations%u SET Flags=Flags|? WHERE Flags&?;" );
	_LIT( KUpdateDeleteContextObjects,   "UPDATE Object%u SET Flags=Flags|? WHERE ObjectId IN ( SELECT ObjectId FROM Object%u AS O WHERE Flags&? AND UsageCount=0 AND ( SELECT count(*) FROM Relations%u WHERE NOT Flags&? AND ( LeftObjectId = O.ObjectId OR RightObjectId = O.ObjectId ) )= 0 );" );
    _LIT( KDeleteWordFromTextSearchDict, "DELETE FROM TextSearchDictionary%u WHERE NOT EXISTS(SELECT WordId FROM TextSearch%u WHERE WordId = TextSearchDictionary%u.WordId);");

	RClauseBuffer commonClauseOne(*this, KUpdateDeleteContextObjects().Length() + 3 * KMaxUintValueLength);
	CleanupClosePushL( commonClauseOne );
	CMdsClauseBuffer& buffer = commonClauseOne.BufferL();

    RRowData rowDataDel;
    CleanupClosePushL( rowDataDel );
    rowDataDel.AppendL( TColumn( EMdEObjectFlagGarbage ) );

   	const RPointerArray<CMdsNamespaceDef>& namespaceDefs = 
   		iSchema.NamespaceDefs();

	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
	TInt deleteObjectResult = 0;
	TInt updateResult = 0;
	
	const TInt count = namespaceDefs.Count();
	
   	for( TInt i = 0; i < count; ++i )
   	    {
   	    const TDefId nmspId = namespaceDefs[i]->GetId();

		// deleting objects
		buffer.BufferL().Format( KDeleteObject, nmspId, nmspId );
   	    User::LeaveIfError( deleteObjectResult = connection.ExecuteL( 
   	    		buffer.ConstBufferL(), rowDataDel ) );
   	    
   	    if( deleteObjectResult > 0 )
   	        {
   	        // If objects were deleted, continue garbage collection 
   	        iDictionaryToBeCleaned = ETrue;
   	        CleanupStack::PopAndDestroy( 2, &commonClauseOne );
   	        return ETrue;
   	        }

   	    RRowData rowDataUpd;
   	    CleanupClosePushL( rowDataUpd );
   	    rowDataUpd.AppendL( TColumn( EMdEObjectFlagGarbage ) );
   	    rowDataUpd.AppendL( TColumn( EMdEObjectFlagRemoved ) );
   	    
        buffer.BufferL().Format( KUpdateDeleteObject, nmspId );
   	    User::LeaveIfError( updateResult += connection.ExecuteL(
   	    		buffer.ConstBufferL(), rowDataUpd ) );

        if( updateResult > 0 )
            {
            // If objects were modified, continue garbage collection 
            CleanupStack::PopAndDestroy( 3, &commonClauseOne );
            return ETrue;
            }

        RRowData rowDataDelRel;
        CleanupClosePushL( rowDataDelRel );
        rowDataDelRel.AppendL( TColumn( EMdERelationFlagGarbageDeleted ) );
        
        RRowData rowDataUpdRel;
        CleanupClosePushL( rowDataUpdRel );
        rowDataUpdRel.AppendL( TColumn( EMdERelationFlagGarbageDeleted ) );
        rowDataUpdRel.AppendL( TColumn( EMdERelationFlagDeleted ) );
        
		// deleting relations
		buffer.BufferL().Format( KDeleteRelations, nmspId );
   	    User::LeaveIfError( connection.ExecuteL( 
   	    		buffer.ConstBufferL(), rowDataDelRel ) );

		buffer.BufferL().Format( KUpdateDeleteRelations, nmspId );
   	    User::LeaveIfError( updateResult += connection.ExecuteL( 
   	    		buffer.ConstBufferL(), rowDataUpdRel ) );
   	    
        if( updateResult > 0 )
            {
            // If objects were modified, continue garbage collection 
            CleanupStack::PopAndDestroy( 5, &commonClauseOne );
            return ETrue;
            }

        RRowData rowDataDelContext;
        CleanupClosePushL( rowDataDelContext );
        rowDataDelContext.AppendL( TColumn( EMdEObjectFlagRemoved ) );
        rowDataDelContext.AppendL( TColumn( EMdEObjectFlagContext ) );
        rowDataDelContext.AppendL( TColumn( EMdERelationFlagDeleted ) );
        
		// deleting context objects
		buffer.BufferL().Format( KUpdateDeleteContextObjects, nmspId, nmspId, nmspId );
   	    User::LeaveIfError( updateResult += connection.ExecuteL( 
   	    		buffer.ConstBufferL(), rowDataDelContext ) );
   	    
        if( updateResult > 0 )
            {
            // If objects were modified, continue garbage collection 
            CleanupStack::PopAndDestroy( 6, &commonClauseOne );
            return ETrue;
            }

        RRowData emptyRow;
        CleanupClosePushL( emptyRow );
        
		// deleting words from text search dictionary
		if ( iDictionaryToBeCleaned )
			{
			buffer.BufferL().Format( KDeleteWordFromTextSearchDict, nmspId, nmspId, 
					nmspId );
	   	    User::LeaveIfError( connection.ExecuteL( 
	   	    		buffer.ConstBufferL(), emptyRow ) );
	   	    iDictionaryToBeCleaned = EFalse;
			}
   	    }

   	// empryRow, rowDataDelContext, rowDataUpdRel, rowDataDelRel, rowDataUpd, 
   	// rowDataDel, commonClauseOne
	CleanupStack::PopAndDestroy( 7, &commonClauseOne );

	// When this is reached, all garbage collection steps have been fully executed
	return EFalse;
	}

void CMdSSqlObjectManipulate::AnalyzeL()
    {
    CMdSSqLiteConnection& db = MMdSDbConnectionPool::GetDefaultDBL();
    db.DoAnalyzeL();
    }

CMdSSqlObjectManipulate::RClauseBuffer::RClauseBuffer( CMdSSqlObjectManipulate& aSOM, TInt aSize )
	: iBuffers( aSOM.iBuffers ), iBuffer( NULL ), iNr( -1 ), iSize( aSize )
	{
	// search for available buffer
	// or create new one
	for (TInt i = 0; i < iBuffers.Count(); ++i)
		{
		if (!iBuffers[i].iLock)
			{
		    iBuffers[i].iLock = ETrue;
            CMdsClauseBuffer* oldBuffer( iBuffer );
            iBuffer = iBuffers[i].iBuffer;
            TRAPD( error, iBuffer->ReserveSpaceL(aSize) );
            if( error != KErrNone )
                {
                iBuffer = oldBuffer;
                iBuffers[i].iLock = EFalse;
                continue;
                }		
            TRAP_IGNORE( iBuffer->BufferL().Zero() );			
			iNr = i;
			return;
			}
		}
	}

CMdsClauseBuffer& CMdSSqlObjectManipulate::RClauseBuffer::BufferL()
	{
	if ( iNr < 0 && !iBuffer )
		{
		iBuffer = CMdsClauseBuffer::NewL( iSize );
		}
	return *iBuffer;
	}

void CMdSSqlObjectManipulate::RClauseBuffer::Close()
	{
	if ( iNr < 0 )
		{
		__ASSERT_DEBUG( iBuffer, _L("RClauseBuffer::Close()") );
		if ( iBuffer )
			{
			delete iBuffer;
			iBuffer = NULL;
			}
		}
	else
		{
		iBuffers[iNr].iLock = EFalse;
		iBuffer = NULL;
		}
	}