metadataengine/server/src/mdsschema.cpp
changeset 0 c53acadfccc6
child 14 646a02f170b9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/metadataengine/server/src/mdsschema.cpp	Mon Jan 18 20:34:07 2010 +0200
@@ -0,0 +1,733 @@
+/*
+* Copyright (c) 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:  Class to hold description about schema
+*
+*/
+
+#include <badesca.h>
+#include "mdsschema.h"
+
+#include "mdcdef.h"
+#include "mdsnamespacedef.h"
+#include "mdsobjectdef.h"
+#include "mdsclausebuffer.h"
+#include "mdsfindsqlclausedef.h"
+#include "mdspropertydef.h"
+#include "mdsdbconnectionpool.h"
+#include "mdssqliteconnection.h"
+#include "mdcserializationbuffer.h"
+#include <mdeconstants.h>
+
+
+/**
+ * NewLC
+ */
+CMdsSchema* CMdsSchema::NewLC( )
+	{
+	CMdsSchema* ret = new( ELeave ) CMdsSchema( );
+	CleanupStack::PushL( ret );
+	ret->ConstructL( );
+	return ret;
+	}
+	
+/**
+ * NewL
+ */
+CMdsSchema* CMdsSchema::NewL( )
+	{
+	CMdsSchema* ret = CMdsSchema::NewLC( );
+	CleanupStack::Pop( ret );
+	return ret;
+	}
+
+/**
+ * ConstructL
+ */
+void CMdsSchema::ConstructL( )
+	{
+	}
+
+/**
+ * Constructor
+ */
+CMdsSchema::CMdsSchema() : iBaseObject( NULL ),
+        iSerialized( EFalse ), iSchemaHandle( 0 )
+	{
+	}
+
+/**
+ * Destructor
+ */
+CMdsSchema::~CMdsSchema()
+	{
+	iNamespaceDefs.ResetAndDestroy();
+	iNamespaceDefs.Close();
+
+	iSerializedSchema.Close();
+	iProperties.Close();
+
+	delete iBaseObject;
+	}
+
+void CMdsSchema::Reset()
+	{
+	// deleting namespaces
+	iNamespaceDefs.ResetAndDestroy();
+	}
+
+void CMdsSchema::AddDefaultObjectL()
+	{
+	
+	iBaseObject = CMdsObjectDef::NewL( MdeConstants::Object::KBaseObject, NULL );
+	iBaseObject->SetId(KBaseObjectDefId);
+	
+	// name, type, min, max, read-only, mandatory, indexed
+	iBaseObject->AddPropertyL( MdeConstants::Object::KOriginProperty, EPropertyUint8, TInt32(0), TInt32(KMaxTUint8), EFalse, EFalse, EFalse );
+	iBaseObject->AddPropertyL( MdeConstants::Object::KSizeProperty, EPropertyUint32, TUint32(0), KMaxTUint32, EFalse, EFalse, EFalse );
+	iBaseObject->AddPropertyL( MdeConstants::Object::KTimeOffsetProperty, EPropertyInt16, TInt32(KMinTInt16), TInt32(KMaxTInt16), ETrue, EFalse, EFalse );
+	iBaseObject->AddPropertyL( MdeConstants::Object::KCreationDateProperty, EPropertyTime, KMinTInt64, KMaxTInt64, EFalse, ETrue, EFalse );
+	iBaseObject->AddPropertyL( MdeConstants::Object::KLastModifiedDateProperty, EPropertyTime, KMinTInt64, KMaxTInt64, EFalse, ETrue, EFalse );
+	iBaseObject->AddPropertyL( MdeConstants::Object::KItemTypeProperty, EPropertyText, TInt32(0), TInt32(255), EFalse, EFalse, EFalse );
+	iBaseObject->AddPropertyL( MdeConstants::Object::KTitleProperty, EPropertyText, TInt32(0), TInt32(255), EFalse, EFalse, EFalse );
+	
+	TInt propcount = iBaseObject->GetPropertiesCount();
+	iBaseObject->iCol2Prop.Reset();
+	
+	for (TInt i = 0 ; i < propcount; i++)
+		{
+		CMdsPropertyDef* propertyDef = iBaseObject->GetProperty(i);
+		propertyDef->SetId(i+1);
+		CMdsObjectDef::TMdsColumnOrder col = 
+			{ i + KBaseObjectBasicValueColumnOffset, *propertyDef };
+		iBaseObject->iCol2Prop.AppendL( col );
+		if( propertyDef->GetMandatory() )
+			{
+			++iBaseObject->iMandatoryPropertyCount;
+			}
+		}
+	}
+
+void CMdsSchema::AddDefaultNamespaceL()
+	{
+	NamespaceAddL( KMdEDefaultNameSpace, EFalse, KNokiaVendorId, KDefaultNamespaceDefId );
+	}
+
+CMdsNamespaceDef* CMdsSchema::NamespaceAddL( const TDesC& aName, const TBool aReadOnly, TInt32 aVendorId, TDefId aNamespaceDefId )
+	{
+	CMdsNamespaceDef* newNamespace = CMdsNamespaceDef::NewLC( aNamespaceDefId, aName, aReadOnly, aVendorId );
+	newNamespace->SetBaseObject( iBaseObject );
+	iNamespaceDefs.AppendL( newNamespace );
+	CleanupStack::Pop( newNamespace );
+	return newNamespace;
+	}
+
+CMdsNamespaceDef* CMdsSchema::GetNamespace( const TDesC& aName )
+	{
+	const TInt count = iNamespaceDefs.Count();
+	
+	for( TInt i = 0; i < count; ++i )
+		{
+		if ( iNamespaceDefs[i]->GetName().Compare( aName ) == 0 )
+			{
+			return iNamespaceDefs[i];
+			}
+		}
+	return NULL;
+	}
+
+const CMdsNamespaceDef* CMdsSchema::GetNamespaceByIdL( TDefId aId )
+	{
+	const TInt namespaceCount = iNamespaceDefs.Count();
+	for ( TInt i = 0; i < namespaceCount; ++i )
+		{
+		if( iNamespaceDefs[i]->GetId() == aId )
+			{
+			return iNamespaceDefs[i];
+			}
+		}
+	return NULL;
+	}
+
+TInt CMdsSchema::NamespaceDefsCount() const
+	{
+	return iNamespaceDefs.Count();
+	}
+
+const RPointerArray<CMdsNamespaceDef>& CMdsSchema::NamespaceDefs() const
+	{
+	return iNamespaceDefs;
+	}
+
+void CMdsSchema::AddObjectToSqlClauseL( CMdsObjectDef* aObject, CMdsClauseBuffer* aClause,
+                                        const TBool& aAddText )
+	{
+	if ( !aObject->iParent )
+		{
+		return;
+		}
+	AddObjectToSqlClauseL( (CMdsObjectDef*)aObject->iParent, aClause, aAddText);
+
+	const TInt objectPropertyCount = aObject->iPropertyDefs.Count();
+	for ( TInt i = 0; i < objectPropertyCount; ++i )
+		{
+		CMdsPropertyDef* propertyDef = aObject->iPropertyDefs[i];
+		// to set up text columns as a last one
+		if ( propertyDef->GetType() == EPropertyText && aAddText == EFalse )
+			{
+			continue;
+			}
+		if ( propertyDef->GetType() != EPropertyText && aAddText )
+			{
+			continue;
+			}
+		// end
+
+		// make object table definition
+		aClause->AppendL( propertyDef->GetName() );
+		aClause->AppendL( KSpace );
+		aClause->AppendL( propertyDef->GetSqlTypeName() );
+		aClause->AppendL( KComma );
+		}
+	}
+
+void CMdsSchema::CreateObjectTablesL()
+	{
+	_LIT( KBaseObjectDefinition,  "CREATE TABLE IF NOT EXISTS %S%u(ObjectId INTEGER PRIMARY KEY AUTOINCREMENT,ObjectDefId INTEGER NOT NULL,Flags INTEGER,MediaId LARGEINT,UsageCount LARGEINT DEFAULT 0,GuidHigh LARGEINT,GuidLow LARGEINT,URI TEXT NOT NULL COLLATE NOCASE,Origin INTEGER,Size LARGEINT,TimeOffset INTEGER,CreationDate LARGEINT,LastModifiedDate LARGEINT,ItemType TEXT,Title TEXT,UNIQUE(GuidHigh,GuidLow),UNIQUE(MediaId,URI));" );	
+	_LIT( KCreateRelationsTable,  "CREATE TABLE IF NOT EXISTS Relations%u(RelationId INTEGER PRIMARY KEY AUTOINCREMENT,Flags INTEGER,RelationDefId INTEGER NOT NULL,LeftObjectId INTEGER NOT NULL,RightObjectId INTEGER NOT NULL,Parameter INTEGER,GuidHigh LARGEINT,GuidLow LARGEINT,LastModifiedDate LARGEINT);" );
+	_LIT( KCreateEventsTable,     "CREATE TABLE IF NOT EXISTS Event%u(EventId INTEGER PRIMARY KEY AUTOINCREMENT,ObjectId INTEGER NOT NULL, EventDefId INTEGER NOT NULL, Timestamp INTEGER NOT NULL, Source TEXT, Participant TEXT);" );
+	_LIT( KCreateTxtSrchTable,    "CREATE TABLE IF NOT EXISTS TextSearch%u(WordId INTEGER NOT NULL,ObjectId INTEGER NOT NULL,Position INTEGER);" );
+	_LIT( KCreateTxtSrchDicTable, "CREATE TABLE IF NOT EXISTS TextSearchDictionary%u(WordId INTEGER PRIMARY KEY,Word TEXT NOT NULL);" );
+
+	_LIT( KMdsSqlClauseObjTableBeg, "CREATE TABLE IF NOT EXISTS %S%u(ObjectId INTEGER NOT NULL," );
+	_LIT( KMdsSqlClauseObjTableEnd, " UNIQUE(ObjectId));" );
+
+    // Triggers
+	_LIT( KMdsTriggerEvent,      "CREATE TRIGGER DeleteEvent%u BEFORE DELETE ON Object%u BEGIN DELETE FROM Event%u WHERE ObjectId=OLD.ObjectId; END;" );
+	_LIT( KMdsTriggerRelation,   "CREATE TRIGGER DeleteRelations%u BEFORE DELETE ON Object%u BEGIN DELETE FROM Relations%u WHERE LeftObjectId=OLD.ObjectId OR RightObjectId=OLD.ObjectId; END;" );
+    _LIT( KMdsTriggerTextSearch, "CREATE TRIGGER DeleteTextSearch%u BEFORE DELETE ON Object%u BEGIN DELETE FROM TextSearch%u WHERE ObjectId=OLD.ObjectId; END;" );	
+
+	// UsageCount relation triggers
+	_LIT( KMdsTriggerInsertRelation, "CREATE TRIGGER InsertRelations%u INSERT ON Relations%u BEGIN UPDATE Object%u SET UsageCount = UsageCount + 1 WHERE ObjectId=NEW.LeftObjectId OR ObjectId=NEW.RightObjectId; END;" );
+	_LIT( KMdsTriggerUpdateRelation, "CREATE TRIGGER UpdateRelations%u UPDATE OF LeftObjectId, RightObjectId ON Relations%u WHEN OLD.Flags=NEW.Flags BEGIN UPDATE Object%u SET UsageCount = UsageCount - 1 WHERE ObjectId=OLD.LeftObjectId OR ObjectId=OLD.RightObjectId; UPDATE Object1 SET UsageCount = UsageCount + 1 WHERE ObjectId=NEW.LeftObjectId OR ObjectId=NEW.RightObjectId; END;" );
+	_LIT( KMdsTriggerUpdateNotRemovedRelation, "CREATE TRIGGER UpdateNotRemovedRelations%u UPDATE OF Flags ON Relations%u WHEN OLD.Flags!=NEW.Flags AND NOT NEW.Flags&%u BEGIN UPDATE Object%u SET UsageCount = UsageCount + 1 WHERE ObjectId=NEW.LeftObjectId OR ObjectId=NEW.RightObjectId; END;" );
+	_LIT( KMdsTriggerUpdateRemovedRelation,    "CREATE TRIGGER UpdateRemovedRelations%u UPDATE OF Flags ON Relations%u WHEN OLD.Flags!=NEW.Flags AND NEW.Flags&%u AND NOT OLD.Flags&%u BEGIN UPDATE Object%u SET UsageCount = UsageCount - 1 WHERE ObjectId=OLD.LeftObjectId OR ObjectId=OLD.RightObjectId; END;" );
+
+	// Relation indexes
+	_LIT( KMdsIndexRelationLeftObjectId,  "CREATE INDEX RelationsLeftObjectIdIndex%u ON Relations%u(LeftObjectId);" );
+	_LIT( KMdsIndexRelationRightObjectId, "CREATE INDEX RelationsRightObjectIdIndex%u ON Relations%u(RightObjectId);" );
+
+	// freetext indexes
+	_LIT( KMdsIndexFreetextWordId,   "CREATE INDEX FreetextWordIdIndex%u ON TextSearch%u(WordId);" );
+	_LIT( KMdsIndexFreetextObjectId, "CREATE INDEX FreetextObjectIdIndex%u ON TextSearch%u(ObjectId);" );
+	
+	// ObjectTypeDefinition index
+	_LIT( KMdsIndexObjectDefId, "CREATE INDEX ObjectDefIndex%u ON Object%u(ObjectDefId);" );
+
+	// create tables
+	CMdsClauseBuffer* clause = CMdsClauseBuffer::NewLC( 1024 );
+	clause->ReserveSpaceL( KBaseObjectDefinition.iTypeLength + 30 ); // maxIntNumberDecimal.Length = 10
+	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
+    RRowData emptyRowData;
+    CleanupClosePushL( emptyRowData );
+
+	// for triggers
+	CMdsClauseBuffer* clauseTrigger = CMdsClauseBuffer::NewLC( 1024 );
+	
+	const TInt namespaceDefCount = iNamespaceDefs.Count();
+	
+	// add objectdef[number] to DB
+	for( TInt i = 0; i < namespaceDefCount; ++i )
+		{
+		CMdsNamespaceDef* namespaceDef = iNamespaceDefs[i];
+		const TDefId namespaceDefId = namespaceDef->GetId();
+
+		if (!namespaceDef->GetTableStoredInDB())
+			{
+			// add base objectdef[number]
+			clause->BufferL().Format( KBaseObjectDefinition, &MdeConstants::Object::KBaseObject, namespaceDefId );
+			TRAP_IGNORE( connection.ExecuteL( clause->ConstBufferL(), emptyRowData ) );			
+
+			// add relations[number]
+			clause->BufferL().Format( KCreateRelationsTable, namespaceDefId );
+			TRAPD( errRel, connection.ExecuteL( clause->ConstBufferL(), emptyRowData ) );
+	        if( errRel == KErrNone )
+	            {
+	            clauseTrigger->ReserveSpaceL( KMdsTriggerRelation().Size() + ( KMaxUintValueLength * 3 ) );  
+	            clauseTrigger->BufferL().Format( KMdsTriggerRelation, namespaceDefId, namespaceDefId, namespaceDefId );
+	            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+	            }
+
+			// add event[number]
+			clause->BufferL().Format( KCreateEventsTable, namespaceDefId );
+			TRAPD( errEve, connection.ExecuteL( clause->ConstBufferL(), emptyRowData ) );
+	        if( errEve == KErrNone )
+	            {
+	            clauseTrigger->ReserveSpaceL( KMdsTriggerEvent().Size() + ( KMaxUintValueLength * 3 ) );  
+	            clauseTrigger->BufferL().Format( KMdsTriggerEvent, namespaceDefId, namespaceDefId, namespaceDefId );
+	            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+	            }
+
+			// add textsearch[number]
+			clause->BufferL().Format( KCreateTxtSrchTable, namespaceDefId );
+			TRAPD( errTS, connection.ExecuteL( clause->ConstBufferL(), emptyRowData ) );
+	        if( errTS == KErrNone )
+	            {
+	            clauseTrigger->ReserveSpaceL( KMdsTriggerTextSearch().Size() + ( KMaxUintValueLength * 3 ) );  
+	            clauseTrigger->BufferL().Format( KMdsTriggerTextSearch, namespaceDefId, namespaceDefId, namespaceDefId );
+	            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+
+				// add KMdsIndexFreetextWordId[number]
+	            clauseTrigger->ReserveSpaceL( KMdsIndexFreetextWordId().Size() + ( KMaxUintValueLength * 2 ) );  
+	            clauseTrigger->BufferL().Format( KMdsIndexFreetextWordId, namespaceDefId, namespaceDefId );
+	            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+				
+				// add KMdsIndexFreetextObjectId[number]
+	            clauseTrigger->ReserveSpaceL( KMdsIndexFreetextObjectId().Size() + ( KMaxUintValueLength * 2 ) );  
+	            clauseTrigger->BufferL().Format( KMdsIndexFreetextObjectId, namespaceDefId, namespaceDefId );
+	            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+	            }
+
+			// add textsearchdictionary[number]
+			clause->BufferL().Format( KCreateTxtSrchDicTable, namespaceDefId );
+			TRAP_IGNORE( connection.ExecuteL( clause->ConstBufferL(), emptyRowData ) );
+			
+			// add insertrelations[number]
+            clauseTrigger->ReserveSpaceL( KMdsTriggerInsertRelation().Size() + ( KMaxUintValueLength * 3 ) );  
+            clauseTrigger->BufferL().Format( KMdsTriggerInsertRelation, namespaceDefId, namespaceDefId, namespaceDefId );
+            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+
+			// add updaterelations[number]
+            clauseTrigger->ReserveSpaceL( KMdsTriggerUpdateRelation().Size() + ( KMaxUintValueLength * 3 ) );  
+            clauseTrigger->BufferL().Format( KMdsTriggerUpdateRelation, namespaceDefId, namespaceDefId, namespaceDefId );
+            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+
+			// add updatenotremovedrelations[number]
+            clauseTrigger->ReserveSpaceL( KMdsTriggerUpdateNotRemovedRelation().Size() + ( KMaxUintValueLength * 4 ) );  
+            clauseTrigger->BufferL().Format( KMdsTriggerUpdateNotRemovedRelation, namespaceDefId, namespaceDefId, 
+                    EMdERelationFlagNotPresent | EMdERelationFlagDeleted, namespaceDefId );
+            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+
+			// add updateremovedrelations[number]
+            clauseTrigger->ReserveSpaceL( KMdsTriggerUpdateRemovedRelation().Size() + ( KMaxUintValueLength * 5 ) );  
+            clauseTrigger->BufferL().Format( KMdsTriggerUpdateRemovedRelation, namespaceDefId, namespaceDefId, EMdERelationFlagNotPresent | EMdERelationFlagDeleted, EMdERelationFlagNotPresent | EMdERelationFlagDeleted, namespaceDefId );
+            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+
+			// add relationleftobjectidindex[number]
+            clauseTrigger->ReserveSpaceL( KMdsIndexRelationLeftObjectId().Size() + ( KMaxUintValueLength * 2 ) );  
+            clauseTrigger->BufferL().Format( KMdsIndexRelationLeftObjectId, namespaceDefId, namespaceDefId );
+            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+
+			// add relationrightobjectidindex[number]
+            clauseTrigger->ReserveSpaceL( KMdsIndexRelationRightObjectId().Size() + ( KMaxUintValueLength * 2 ) );  
+            clauseTrigger->BufferL().Format( KMdsIndexRelationRightObjectId, namespaceDefId, namespaceDefId );
+            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+
+            // add objectdefidindex[number]
+            clauseTrigger->ReserveSpaceL( KMdsIndexObjectDefId().Size() + ( KMaxUintValueLength * 2 ) );  
+            clauseTrigger->BufferL().Format( KMdsIndexObjectDefId, namespaceDefId, namespaceDefId );
+            connection.ExecuteL( clauseTrigger->ConstBufferL(), emptyRowData );
+            
+			namespaceDef->SetTableStoredInDB();
+			}
+
+		const TInt objectDefCount = namespaceDef->iObjectDefs.Count();
+		
+		for ( TInt j = 0; j < objectDefCount; ++j )
+			{
+			CMdsObjectDef* objectDef = namespaceDef->iObjectDefs[j];
+
+			if (!objectDef->GetTableStoredInDB())
+				{
+				clause->BufferL().Format( KMdsSqlClauseObjTableBeg, &objectDef->GetName(), namespaceDef->GetId() );
+
+				// add no text properties
+				AddObjectToSqlClauseL( objectDef, clause, EFalse );
+				// add text properties at end
+				AddObjectToSqlClauseL( objectDef, clause, ETrue );
+
+				clause->AppendL( KMdsSqlClauseObjTableEnd );
+				TRAP_IGNORE( connection.ExecuteL( clause->ConstBufferL(), emptyRowData ) );
+
+				objectDef->SetTableStoredInDB();
+				}
+
+			const TInt objectPropertyCount = objectDef->iPropertyDefs.Count();
+			for ( TInt k = 0; k < objectPropertyCount; ++k )
+				{
+				CMdsPropertyDef* propertyDef = objectDef->iPropertyDefs[k];
+				
+				if ( propertyDef->GetIndexed() )
+					{
+					iProperties.AppendL( TPropertyInfo( objectDef->GetName(), 
+							propertyDef->GetName(), namespaceDef->GetId() ) );
+					}
+				}
+			}
+        iProperties.AppendL( TPropertyInfo( MdeConstants::Object::KBaseObject, MdeConstants::Object::KItemTypeProperty, namespaceDef->GetId() ) );
+		}
+
+	CleanupStack::PopAndDestroy( 3, clause ); // clauseTrigger, emptyRowData, clause
+	}
+
+void CMdsSchema::CreatePropertyIndexL( const TDesC& aPropertyName, const TDesC& aTableName, 
+		TDefId aNamespaceId )
+	{
+	_LIT( KMdsPropertyIndexCreate, "CREATE INDEX %S%SIndex%u ON %S%u(%S);" );
+	
+	const TUint clauseLength = KMdsPropertyIndexCreate.iTypeLength + aTableName.Length() * 2 +
+		+ aPropertyName.Length() * 2 + KMaxUintValueLength * 2;
+	CMdsClauseBuffer* clause = CMdsClauseBuffer::NewLC( clauseLength );
+	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
+    RRowData emptyRowData;
+    CleanupClosePushL( emptyRowData );
+    clause->BufferL().Format( KMdsPropertyIndexCreate, &aTableName, &aPropertyName, aNamespaceId,
+    		&aTableName, aNamespaceId, &aPropertyName );
+	TRAP_IGNORE( connection.ExecuteL( clause->ConstBufferL(), emptyRowData ) );
+	CleanupStack::PopAndDestroy( 2, clause ); // emptyRowData, clause
+	}
+
+void CMdsSchema::StoreToDBL()
+	{
+	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
+    RMdSTransaction transaction( connection );
+    CleanupClosePushL( transaction );
+    User::LeaveIfError( transaction.Error() );
+
+	StoreNamespacesAndBaseObjectL();
+    CreateObjectTablesL();
+	StoreSchemaToDBL();
+	CreateCol2PropTableL();
+
+    transaction.CommitL();
+    CleanupStack::PopAndDestroy( &transaction );
+    
+    TUint propertyCount = iProperties.Count();
+    for ( TUint i = 0; i < propertyCount; ++i )
+    	{
+    	TPropertyInfo& propertyInfo = iProperties[i];
+    	CreatePropertyIndexL( propertyInfo.iPropertyName, propertyInfo.iTableName,
+    			propertyInfo.iNamespaceId );
+    	}
+    iProperties.Reset();
+	}
+
+void CMdsSchema::AddCol2PropObjectL( CMdsObjectDef* aObject, CMdsObjectDef* aChildObject,
+									 TUint32& aPropertyColumnCounter, TBool aText )
+	{
+	_LIT( KMdsSqlClauseAddCol2Prop, "INSERT INTO Col2Prop(ObjectDefId,PropertyDefId,ColumnId) Values(?,?,?);" );
+	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
+	if ( !aChildObject->iParent )
+		{
+		if (aText)
+			{
+			return;
+			}
+		RRowData rowData;
+		CleanupClosePushL( rowData );
+		const TInt childObjectPropertyCount = aChildObject->iPropertyDefs.Count();
+		for ( TInt i = 0; i < childObjectPropertyCount; ++i )
+			{
+			CMdsPropertyDef* propertyDef = aChildObject->iPropertyDefs[i];
+			CMdsObjectDef::TMdsColumnOrder col = { aChildObject->iCol2Prop[i].iColumnId, *propertyDef };
+			aObject->iCol2Prop.AppendL( col );
+			
+			if( propertyDef->GetMandatory() )
+				{
+				++aObject->iMandatoryPropertyCount;
+				}
+			
+			++aPropertyColumnCounter;
+			rowData.Reset();
+			rowData.AppendL( TColumn( aObject->GetId() ) );
+			rowData.AppendL( TColumn( propertyDef->GetId() ) );
+			rowData.AppendL( TColumn( col.iColumnId ) );
+			connection.ExecuteL( KMdsSqlClauseAddCol2Prop, rowData );
+			}
+		CleanupStack::PopAndDestroy( &rowData );
+		return;
+		}
+
+	AddCol2PropObjectL( aObject, (CMdsObjectDef*)aChildObject->iParent, aPropertyColumnCounter, aText );
+
+	// if parent is baseobject
+	if ( !aText && !aChildObject->iParent->iParent )
+		{
+		++aPropertyColumnCounter;
+		}
+
+	RRowData rowData;
+	CleanupClosePushL( rowData );
+
+	const TInt childObjectPropertyCount = aChildObject->iPropertyDefs.Count();
+	for ( TInt i = 0; i < childObjectPropertyCount; ++i )
+		{
+		CMdsPropertyDef* propertyDef = aChildObject->iPropertyDefs[i];
+		CMdsObjectDef::TMdsColumnOrder col = { 0, *propertyDef };
+		if (  aText && propertyDef->GetType() != EPropertyText ||
+			 !aText && propertyDef->GetType() == EPropertyText )
+			{
+			continue;
+			}
+
+		col.iColumnId = aPropertyColumnCounter++;
+
+		aObject->iCol2Prop.AppendL( col );
+
+		if( propertyDef->GetMandatory() )
+			{
+			++aObject->iMandatoryPropertyCount;
+			}
+
+		rowData.Reset();
+		rowData.AppendL( TColumn( aObject->GetId() ) );
+		rowData.AppendL( TColumn( propertyDef->GetId() ) );
+		rowData.AppendL( TColumn( col.iColumnId ) );
+		connection.ExecuteL( KMdsSqlClauseAddCol2Prop, rowData );
+		}
+
+	CleanupStack::PopAndDestroy( &rowData );
+	}
+
+void CMdsSchema::CreateCol2PropTableL()
+	{
+	_LIT( KMdsSqlClauseCol2Prop,       "CREATE TABLE IF NOT EXISTS Col2Prop(ObjectDefId INTEGER NOT NULL,PropertyDefId INTEGER NOT NULL,ColumnId INTEGER NOT NULL);" );
+
+    RRowData emptyRowData;
+    CleanupClosePushL( emptyRowData );
+
+	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
+	// create binding column <--> property table
+	connection.ExecuteL( KMdsSqlClauseCol2Prop, emptyRowData );
+	TUint32 propertyColumnCounter;
+
+	const TInt count = iNamespaceDefs.Count();
+	
+	for( TInt i = 0; i < count; ++i )
+		{
+		CMdsNamespaceDef* namespaceDef = iNamespaceDefs[i];
+		const TInt namespaceObjectCount = namespaceDef->iObjectDefs.Count();
+		for ( TInt j = 0; j < namespaceObjectCount; ++j )
+			{
+			CMdsObjectDef* objectDef = namespaceDef->iObjectDefs[j];
+			if (!objectDef->GetC2PStoredInDB())
+				{
+				propertyColumnCounter = KBaseObjectBasicValueColumnOffset;
+
+				objectDef->iCol2Prop.Reset();
+				objectDef->iMandatoryPropertyCount = 0;
+
+				AddCol2PropObjectL( objectDef, objectDef, propertyColumnCounter, EFalse );
+				AddCol2PropObjectL( objectDef, objectDef, propertyColumnCounter, ETrue );
+				objectDef->SetC2PStoredInDB();
+				}
+			}
+		}
+	CleanupStack::PopAndDestroy( &emptyRowData );
+	}
+
+void CMdsSchema::StoreNamespacesAndBaseObjectL()
+	{
+	_LIT( KMdsSqlClauseNamespaceDef, "CREATE TABLE IF NOT EXISTS NamespaceDef(NamespaceDefId INTEGER PRIMARY KEY,ReadOnly INTEGER,VendorId INTEGER,Name TEXT);" );
+	_LIT( KMdsSqlClauseObjectDef,    "CREATE TABLE IF NOT EXISTS ObjectDef(ObjectDefId INTEGER PRIMARY KEY,NamespaceDefId INTEGER NOT NULL,ParentDefId INTEGER NOT NULL,Flags INTEGER,Name TEXT);" );
+	_LIT( KMdsSqlClausePropertyDef,  "CREATE TABLE IF NOT EXISTS PropertyDef(PropertyDefId INTEGER PRIMARY KEY,ObjectDefId INTEGER NOT NULL,Flags INTEGER,Type INTEGER,MinValue NUMERIC,MaxValue NUMERIC,Name TEXT);" );
+	_LIT( KMdsSqlClauseRelationDef,  "CREATE TABLE IF NOT EXISTS RelationDef(RelationDefId INTEGER PRIMARY KEY,NamespaceDefId INTEGER NOT NULL,Name TEXT);" );
+	_LIT( KMdsSqlClauseEventDef,     "CREATE TABLE IF NOT EXISTS EventDef(EventDefId INTEGER PRIMARY KEY,NamespaceDefId INTEGER NOT NULL,Priority INTEGER,Name TEXT);" );
+
+    RRowData emptyRowData;
+    CleanupClosePushL( emptyRowData );
+
+	// create tables
+	const TUint KNumClauses = 5;
+
+	CDesCArrayFlat* descarray = new (ELeave) CDesCArrayFlat(KNumClauses);
+	CleanupStack::PushL(descarray);
+	descarray->AppendL(KMdsSqlClauseNamespaceDef);
+	descarray->AppendL(KMdsSqlClauseObjectDef);
+	descarray->AppendL(KMdsSqlClausePropertyDef);
+	descarray->AppendL(KMdsSqlClauseRelationDef);
+	descarray->AppendL(KMdsSqlClauseEventDef);
+
+	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
+
+	TInt error;
+	for (TUint i = 0; i < KNumClauses; i++)
+		{
+		TRAP( error,connection.ExecuteL( (*descarray)[i], emptyRowData ) );
+		if ( error != KErrNone && error != KSqlErrGeneral )
+			{
+			User::Leave( error );
+			}
+		}
+	descarray->Reset();
+	CleanupStack::PopAndDestroy( descarray );
+
+	const TInt count = iNamespaceDefs.Count();
+	
+	// add only namespaceDef to DB
+	for( TInt i = 0; i < count; ++i )
+		{
+		iNamespaceDefs[i]->StoreToDBL( ETrue );
+		}
+
+	CleanupStack::PopAndDestroy( &emptyRowData );
+	}
+
+void CMdsSchema::StoreSchemaToDBL()
+	{
+	_LIT( KMdsSqlClauseDeleteBoFromOd,  "DELETE FROM ObjectDef WHERE ObjectDefId=?;" );
+	_LIT( KMdsSqlClauseDeleteBoFromPd,  "DELETE FROM PropertyDef WHERE ObjectDefId=?;" );
+
+	iBaseObject->StoreToDBL( KNoDefId );
+	
+	const TInt count = iNamespaceDefs.Count();
+	
+	// add namespaceDef to DB
+	for( TInt i = 0; i < count; ++i )
+		{
+		iNamespaceDefs[i]->StoreToDBL();
+		}
+
+	RRowData removeBo;
+	CleanupClosePushL( removeBo );
+	removeBo.AppendL( TColumn( KBaseObjectDefId ) );
+
+	CMdSSqLiteConnection& connection = MMdSDbConnectionPool::GetDefaultDBL();
+	TRAPD( err, connection.ExecuteL( KMdsSqlClauseDeleteBoFromOd,  removeBo ) );
+	TRAP ( err, connection.ExecuteL( KMdsSqlClauseDeleteBoFromPd,  removeBo ) );
+	
+	CleanupStack::PopAndDestroy( &removeBo );	
+	}
+
+void CMdsSchema::MergeElementsL( CMdsSchema& aSchema, const TBool& aDryRun )
+	{
+	const TInt count = aSchema.iNamespaceDefs.Count();
+	
+	for ( TInt i = 0; i < count; ++i )
+		{
+		CMdsNamespaceDef* lNamespace = NULL;
+		CMdsNamespaceDef* rNamespace = aSchema.iNamespaceDefs[i];
+		// reseting after namespace read from file
+		rNamespace->UnsetFirstRead();
+		// search for namespace
+        lNamespace = GetNamespace( rNamespace->GetName() );
+		if ( !lNamespace )
+			{
+			if ( !aDryRun )
+				{
+				// just add pointer to new schema and remove it from old one
+				iNamespaceDefs.AppendL( rNamespace );
+				aSchema.iNamespaceDefs[i] = NULL;
+				rNamespace->SetAllNotStoredInDB();
+				}
+			}
+		else
+			{
+			// copy appropriate elements
+			if ( lNamespace->GetVendorId() == rNamespace->GetVendorId() && !lNamespace->GetReadOnly() )
+				{
+				lNamespace->MergeObjectsL( rNamespace, aDryRun );
+				lNamespace->MergeEventsL( rNamespace, aDryRun );
+				lNamespace->MergeRelationsL( rNamespace, aDryRun );
+				}
+			else
+				{
+				User::Leave( KErrAccessDenied );
+				}
+			}
+		}
+	}
+
+void CMdsSchema::MergeNamespacesL( CMdsSchema& aSchema )
+	{
+	if ( iNamespaceDefs.Count() == 0 )
+		{// speed optimization
+		Reset();
+		
+		const TInt count = aSchema.iNamespaceDefs.Count();
+		
+		for ( TInt i = 0; i < count; ++i )
+			{
+			// reseting after namespace read from file
+			aSchema.iNamespaceDefs[i]->UnsetFirstRead();
+			iNamespaceDefs.AppendL( aSchema.iNamespaceDefs[i] );
+			aSchema.iNamespaceDefs[i] = NULL;
+			}
+		aSchema.Reset();
+		}
+	else
+		{
+		MergeElementsL( aSchema, ETrue );
+		MergeElementsL( aSchema, EFalse );
+		}
+	}
+
+void CMdsSchema::SerializeToSharedMemoryL()
+	{
+	const TInt namespaceCount = iNamespaceDefs.Count();
+
+	// namespace count, namespace offsets
+	TUint32 bufferSize = sizeof(TMdCSchema) + namespaceCount * sizeof(TMdCNamespaceDef);
+
+	for ( TInt i = 0; i < namespaceCount; ++i )
+		{
+		bufferSize += iNamespaceDefs[i]->RequiredBufferSize();
+		}
+
+	// create shared memory chunk
+	iSerialized = EFalse;
+	iSerializedSchema.Close();
+	++iSchemaHandle;
+	HBufC* name = HBufC::NewLC( KSchemaChunkName.iTypeLength + KMaxUintValueLength );
+	*name = KSchemaChunkName;
+	name->Des().AppendNum( iSchemaHandle );
+
+	TInt error = KErrNone;
+	while( (error = iSerializedSchema.CreateGlobal( *name, bufferSize, bufferSize )) == KErrAlreadyExists )
+		{
+		++iSchemaHandle;
+		*name = KSchemaChunkName;
+		name->Des().AppendNum( iSchemaHandle );
+		}
+	User::LeaveIfError( error );
+
+	CMdCSerializationBuffer* buffer = CMdCSerializationBuffer::NewLC( iSerializedSchema.Base(), bufferSize );
+
+	TMdCSchema schema;
+	schema.iNamespaceDefs.iPtr.iCount = namespaceCount;
+	schema.iNamespaceDefs.iPtr.iOffset = sizeof(schema);
+	schema.SerializeL( *buffer );
+
+	TMdCOffset freeSpace = schema.iNamespaceDefs.iPtr.iOffset + namespaceCount * sizeof(TMdCNamespaceDef);
+	for ( TInt i = 0; i < namespaceCount; ++i )
+		{
+		buffer->PositionL( schema.iNamespaceDefs.iPtr.iOffset + i * sizeof(TMdCNamespaceDef) );
+
+		// write namespace
+		freeSpace = iNamespaceDefs[i]->SerializeL( *buffer, freeSpace );
+		}
+
+	CleanupStack::PopAndDestroy( buffer );
+	CleanupStack::PopAndDestroy( name );
+	iSerialized = ETrue;
+	}
+	
+TInt CMdsSchema::SharedMemoryHandleL()
+	{
+	if ( !iSerialized )
+		{
+		User::Leave( KErrNotReady );
+		}
+	return iSchemaHandle;
+	}
+