phonebookengines/contactsmodel/cntplsql/src/cpplgroupstable.cpp
changeset 0 e686773b3f54
child 24 0ba2181d7c28
equal deleted inserted replaced
-1:000000000000 0:e686773b3f54
       
     1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "pltables.h"
       
    17 #include "dbsqlconstants.h"
       
    18 
       
    19 
       
    20 const TInt KArrayGranularity = 4;
       
    21 
       
    22 /**
       
    23 @param aDatabase A handle to the database.
       
    24 
       
    25 @return A pointer to a new CPplGroupsTable object.
       
    26 */
       
    27 CPplGroupsTable* CPplGroupsTable::NewL(RSqlDatabase& aDatabase)
       
    28 	{
       
    29 	CPplGroupsTable* self = CPplGroupsTable::NewLC(aDatabase);
       
    30 	CleanupStack::Pop(self);
       
    31 	return self;
       
    32 	}
       
    33 
       
    34 /**
       
    35 @param aDatabase A handle to the database.
       
    36 
       
    37 @return A pointer to a new CPplGroupsTable object.
       
    38 */
       
    39 CPplGroupsTable* CPplGroupsTable::NewLC(RSqlDatabase& aDatabase)
       
    40 	{
       
    41 	CPplGroupsTable* self = new (ELeave) CPplGroupsTable(aDatabase);
       
    42 	CleanupStack::PushL(self);
       
    43 	self->ConstructL();
       
    44 	return self;
       
    45 	}
       
    46 
       
    47 /**
       
    48 Set up the CCntSqlStatement objects held by the class.
       
    49 */
       
    50 void CPplGroupsTable::ConstructL()
       
    51 	{
       
    52 	// Statement types
       
    53 	TCntSqlStatementType insertType(EInsert, KSqlContactGroupTableName);
       
    54 	TCntSqlStatementType selectType(ESelect, KSqlContactGroupTableName);
       
    55 	TCntSqlStatementType updateType(EUpdate, KSqlContactGroupTableName);
       
    56 	TCntSqlStatementType deleteType(EDelete, KSqlContactGroupTableName);
       
    57 	TCntSqlStatementType countContactsType(ESelect, KSqlContactTableName);
       
    58 	
       
    59 	// Where clauses
       
    60 
       
    61 	// sizes of the clauses
       
    62 	const TInt KWhereGroupClauseBufSize(KGroupContactGroupId().Size() + 
       
    63 		KWhereStringEqualsStringFormatText().Size() + KGroupContactGroupIdParam().Size() );
       
    64 	const TInt KWhereMemberClauseBufSize(KGroupContactGroupMemberId().Size() + 
       
    65 		KWhereStringEqualsStringFormatText().Size() + KGroupContactGroupMemberIdParam().Size() );
       
    66 	const TInt KWhereOrClauseBufSize(KWhereGroupClauseBufSize + KSqlOr().Size() + KWhereMemberClauseBufSize);
       
    67 	
       
    68 	// for WHERE contact_group_id = [contact id value]
       
    69 	HBufC* whereGroupIdClause = HBufC::NewLC(KWhereGroupClauseBufSize);
       
    70 	whereGroupIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText, 
       
    71 		&KGroupContactGroupId, &KGroupContactGroupIdParam );
       
    72 
       
    73 	// for WHERE contact_group_member_id = [contact id value]
       
    74 	HBufC* whereMemberIdClause = HBufC::NewLC(KWhereMemberClauseBufSize);
       
    75 	whereMemberIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText, 
       
    76 		&KGroupContactGroupMemberId, &KGroupContactGroupMemberIdParam );
       
    77 
       
    78 	// for WHERE contact_group_id = [contact id value] 
       
    79 	//	OR contact_group_member_id = [contact id value]
       
    80 	HBufC* whereGroupOrMemberIdClause = HBufC::NewLC(KWhereOrClauseBufSize);
       
    81 	TPtr whereGroupOrMemberIdClausePtr = whereGroupOrMemberIdClause->Des();
       
    82 	whereGroupOrMemberIdClausePtr.AppendFormat(KWhereStringEqualsStringFormatText, 
       
    83 		&KGroupContactGroupId, &KGroupContactGroupIdParam);
       
    84 	whereGroupOrMemberIdClausePtr.Append(KSqlOr);
       
    85 	whereGroupOrMemberIdClausePtr.AppendFormat(KWhereStringEqualsStringFormatText, 
       
    86 		&KGroupContactGroupMemberId, &KGroupContactGroupMemberIdParam);
       
    87 
       
    88 	// for WHERE contact_id = [contact_id]
       
    89 	HBufC* whereContactIdClause = HBufC::NewLC(KWhereGroupClauseBufSize);
       
    90 	whereContactIdClause->Des().AppendFormat(KWhereStringEqualsStringFormatText, 
       
    91 		&KContactId, &KContactIdParam );
       
    92 		
       
    93 	// INSERT
       
    94 
       
    95 	// insert group-member relationships
       
    96 	// For a statement in the following format:
       
    97 	// 	INSERT INTO groups 
       
    98 	//		(group_id, contact_group_id, contact_group_member_id) 
       
    99 	//		VALUES (NULL, [contact group id value], [contact group member id value]);
       
   100 	//
       
   101 	iInsertStmnt = TSqlProvider::GetSqlStatementL(insertType);
       
   102 	iInsertStmnt->SetParamL(KGroupContactGroupId(), KGroupContactGroupIdParam());
       
   103 	iInsertStmnt->SetParamL(KGroupContactGroupMemberId(), KGroupContactGroupMemberIdParam());
       
   104 
       
   105 	// SELECT
       
   106 	
       
   107 	// select group id
       
   108 	// For a statement in the following format:
       
   109 	// 	SELECT contact_group_id FROM groups 
       
   110 	//		WHERE contact_group_member_id = [contact id value];
       
   111 	//
       
   112 	iSelectGroupsStmnt = TSqlProvider::GetSqlStatementL(selectType);
       
   113 	iSelectGroupsStmnt->SetParamL(KGroupContactGroupId(), KNullDesC() );
       
   114 	iSelectGroupsStmnt->SetConditionL(*whereMemberIdClause);
       
   115 
       
   116 	// select member id
       
   117 	// For a statement in the following format:
       
   118 	// 	SELECT contact_group_member_id FROM groups 
       
   119 	//		WHERE contact_group_id = [contact id value];
       
   120 	//
       
   121 	iSelectMembersStmnt = TSqlProvider::GetSqlStatementL(selectType);
       
   122 	iSelectMembersStmnt->SetParamL(KGroupContactGroupMemberId(), KNullDesC() );
       
   123 	iSelectMembersStmnt->SetConditionL(*whereGroupIdClause);
       
   124 
       
   125 	// DELETE
       
   126 
       
   127 	// delete all where group or member equals id
       
   128 	// For a statement in the following format:
       
   129 	// 	DELETE FROM groups WHERE contact_group_id = [contact id value]
       
   130 	//		OR contact_group_member_id = [contact id value];
       
   131 	//
       
   132 	iDeleteStmnt = TSqlProvider::GetSqlStatementL(deleteType);
       
   133 	iDeleteStmnt->SetConditionL(*whereGroupOrMemberIdClause);
       
   134 
       
   135 	// SELECT
       
   136 	
       
   137 	// SELECt count(*) FROM contact WHERE contact_id = [contact_id]
       
   138 	iCountContactsStmnt = TSqlProvider::GetSqlStatementL(countContactsType);
       
   139 	iCountContactsStmnt->SetParamL(KSqlCount, KSpace);
       
   140 	iCountContactsStmnt->SetConditionL(*whereContactIdClause);
       
   141 	
       
   142 	CleanupStack::PopAndDestroy(4, whereGroupIdClause); // and whereContactIdClause, whereMemberIdClause, whereGroupOrMemberIdClause
       
   143 	}
       
   144 
       
   145 
       
   146 /**
       
   147 Destructor
       
   148 
       
   149 Tidy up CCntSqlStatement objects
       
   150 */
       
   151 CPplGroupsTable::~CPplGroupsTable()
       
   152 	{
       
   153 	delete iInsertStmnt;
       
   154 	delete iSelectGroupsStmnt;
       
   155 	delete iSelectMembersStmnt;
       
   156 	delete iDeleteStmnt;
       
   157 	delete iCountContactsStmnt;
       
   158 	}
       
   159 
       
   160 
       
   161 /**
       
   162 Does nothing. An empty implementation to override the pure virtual method in the base class.
       
   163 */
       
   164 void CPplGroupsTable::CreateInDbL(CContactItem& /*aItem*/)
       
   165 	{
       
   166 	// Do nothing.
       
   167 	
       
   168 	// Inserting new records in the groups table is done through the UpdateL() method.
       
   169 	}
       
   170 
       
   171 
       
   172 /**
       
   173 ReadL has a dual functionality. If passed parameter is a group, will be filled to contacts
       
   174 bellonging to that group. Otherwirse, the contact item will be filed with all groups to which
       
   175 it belongs
       
   176 
       
   177 @param aItem Reference to contact item.
       
   178 */
       
   179 void CPplGroupsTable::ReadL(CContactItem& aItem)
       
   180 	{
       
   181 	const TContactItemId KItemId(aItem.Id() );
       
   182 	const TUid KType(aItem.Type() );
       
   183 	if (KType == KUidContactGroup)
       
   184 		{
       
   185 		CContactGroup& group = static_cast<CContactGroup&>(aItem);
       
   186 		group.ResetItems();
       
   187 		group.SetItems(GetListForItemL(KItemId, ETrue));
       
   188 		}	
       
   189 
       
   190 
       
   191 	if (KType == KUidContactCard || KType == KUidContactOwnCard || KType == KUidContactICCEntry || KType == KUidContactGroup)
       
   192 		{
       
   193 		CContactItemPlusGroup& item = static_cast<CContactItemPlusGroup&>(aItem);
       
   194 		item.ResetGroups();
       
   195 		item.SetGroups(GetListForItemL(KItemId, EFalse));
       
   196 		}	
       
   197 	}
       
   198 
       
   199 
       
   200 /**
       
   201 Updates informations related to passed contact item within group table
       
   202 
       
   203 @param aItem Reference to contact item.
       
   204 */
       
   205 void CPplGroupsTable::UpdateL(const CContactItem& aItem)
       
   206 	{
       
   207 	// Only write to the table if it's a group. If we add the relationship from both sides 
       
   208 	// (i.e. once for the group and once for the item) we will have duplicate records.	
       
   209 	if (aItem.Type() == KUidContactGroup)
       
   210 		{
       
   211 		WriteGroupMembersL(aItem);
       
   212 		}	
       
   213 	}
       
   214 
       
   215 
       
   216 /**
       
   217 Deletes group informations related to passed contact item from group table
       
   218 
       
   219 @param aItem Reference to contact item.
       
   220 @param aLowDiskErrorOccurred out parameter; will be set to ETrue if there was an attempt to delete
       
   221 		in low disk condition
       
   222 */
       
   223 void CPplGroupsTable::DeleteL(const CContactItem& aItem, TBool& aLowDiskErrorOccurred)
       
   224 	{
       
   225 	DeleteItemL(aItem.Id(), aLowDiskErrorOccurred);
       
   226 	}
       
   227 
       
   228 
       
   229 /**
       
   230 Creates the groups table and its indexes in the database.
       
   231 */
       
   232 void CPplGroupsTable::CreateTableL()
       
   233 	{
       
   234 	User::LeaveIfError(iDatabase.Exec(KGroupsCreateStmnt() ) );
       
   235 	}
       
   236 
       
   237 
       
   238 /**
       
   239 CPplGroupsTable constructor 
       
   240 
       
   241 @param aDatabase reference to contact database
       
   242 */
       
   243 CPplGroupsTable::CPplGroupsTable(RSqlDatabase& aDatabase) :
       
   244 	iDatabase(aDatabase)
       
   245 	{
       
   246 	}
       
   247 
       
   248 
       
   249 /**
       
   250 GetListForItemL has a dual nature. If aIsGroup is ETrue, a list of contact items belonging to
       
   251 specified group is returned. Otherwise a list of group ids to which contact id belongs is returned.
       
   252 
       
   253 @param aItemId contact item id
       
   254 @param aIsGroup ETrue if the method will fill a group.
       
   255 */
       
   256 CContactIdArray* CPplGroupsTable::GetListForItemL(TContactItemId aItemId, TBool aIsGroup)
       
   257 	{
       
   258 	/*
       
   259 	// Check if group membership information was not requested or if the item
       
   260 	// is not derived from CContactItemPlusGroup.
       
   261 	if (!(aType == KUidContactGroup	  || aType == KUidContactCard ||
       
   262 		  aType == KUidContactOwnCard || aType == KUidContactICCEntry) )
       
   263 		{
       
   264 		return NULL; 
       
   265 		}
       
   266 	*/	
       
   267 
       
   268 	// build the RSqlStatement
       
   269 	RSqlStatement stmnt;
       
   270 	CleanupClosePushL(stmnt);
       
   271 	TInt idIndex;
       
   272 
       
   273 	// build the CCntSqlStatement statement
       
   274 	const TInt KWhereParamIndex(KFirstIndex); // only one parameter in the query
       
   275 	if (aIsGroup)
       
   276 		{
       
   277 		// group -> select members
       
   278 		stmnt.PrepareL(iDatabase, iSelectMembersStmnt->SqlStringL() );
       
   279 		User::LeaveIfError(stmnt.BindInt(KWhereParamIndex, aItemId ) );
       
   280 		idIndex = stmnt.ColumnIndex(KGroupContactGroupMemberId() );
       
   281 		}
       
   282 	else
       
   283 		{
       
   284 		// member -> select groups
       
   285 		stmnt.PrepareL(iDatabase, iSelectGroupsStmnt->SqlStringL() );
       
   286 		User::LeaveIfError(stmnt.BindInt(KWhereParamIndex, aItemId ) );
       
   287 		idIndex = stmnt.ColumnIndex(KGroupContactGroupId() );
       
   288 		}
       
   289 	User::LeaveIfError(idIndex);
       
   290 	// fetch the list of any matching ids
       
   291 	CContactIdArray* items = CContactIdArray::NewLC();
       
   292 	TInt err(KErrNone);
       
   293 	while ((err = stmnt.Next() ) == KSqlAtRow)
       
   294 		{
       
   295 		items->AddL(stmnt.ColumnInt(idIndex) );
       
   296 		}
       
   297 
       
   298 	// leave if we didn't complete going through the results properly
       
   299 	if(err != KSqlAtEnd)
       
   300 		{
       
   301 		User::Leave(err);
       
   302 		}
       
   303 	
       
   304 	CleanupStack::Pop(items);
       
   305 	CleanupStack::PopAndDestroy(&stmnt);
       
   306 	return items;
       
   307 	}
       
   308 
       
   309 
       
   310 /**
       
   311 Persist the items belonging to curent group into group table
       
   312 
       
   313 @param aGroup referece to a contact group
       
   314 */
       
   315 void CPplGroupsTable::WriteGroupMembersL(const CContactItem& aGroup)
       
   316 	{
       
   317 	if (aGroup.Type() != KUidContactGroup)
       
   318 		{
       
   319 		return;
       
   320 		}
       
   321 
       
   322 	const TContactItemId KGroupId(aGroup.Id() );
       
   323 
       
   324 	// make sure we clear out any previous, out-of-date data
       
   325 	TBool lowDiskErr(EFalse);
       
   326 	DeleteItemL(KGroupId, lowDiskErr);
       
   327 	if (lowDiskErr)
       
   328 		{
       
   329 		User::Leave(KErrDiskFull);
       
   330 		}
       
   331 
       
   332 	// build the RSqlStatement
       
   333 	RSqlStatement stmnt;
       
   334 	CleanupClosePushL(stmnt);
       
   335 	stmnt.PrepareL(iDatabase, iInsertStmnt->SqlStringL() );
       
   336 	const TInt KGroupIdIndex(KFirstIndex); 			// first parameter in query...	
       
   337 	const TInt KMemberIdIndex(KGroupIdIndex + 1); 	// ...and the second parameter
       
   338 	
       
   339 	// copy and sort the member id array so we can see if there are duplicates
       
   340 	const CContactIdArray* contactIdArray = static_cast<const CContactGroup&>(aGroup).ItemsContained();  //does not take the ownership
       
   341 	
       
   342 	const TInt arrayCount = contactIdArray->Count();
       
   343 	CArrayFixFlat<TContactItemId>* sortedList = new(ELeave) CArrayFixFlat<TContactItemId>(KArrayGranularity);	
       
   344 	CleanupStack::PushL(sortedList);
       
   345     for(TInt loop = 0;loop < arrayCount; ++loop)
       
   346     	{
       
   347     	sortedList->AppendL((*contactIdArray)[loop]);		
       
   348     	}
       
   349 	TKeyArrayFix key(0,ECmpTInt);
       
   350 	sortedList->Sort(key);
       
   351 
       
   352 	// insert the group-member relationships
       
   353 	const TInt KCountStmntParamIndex(KFirstIndex); // first and only parameter in query
       
   354 	const TInt listLen(sortedList->Count() );
       
   355 	TInt lastId(0);
       
   356 	for (TInt i = 0; i < listLen; ++i)
       
   357 		{
       
   358 		TInt itemId((*sortedList)[i]);
       
   359 		
       
   360 		//check if a contact item with itemId id really exists in contact database
       
   361 		RSqlStatement countStmnt;
       
   362 		CleanupClosePushL(countStmnt);
       
   363 		countStmnt.PrepareL(iDatabase, iCountContactsStmnt->SqlStringL() );
       
   364 		User::LeaveIfError(countStmnt.BindInt(KCountStmntParamIndex, itemId) );
       
   365 		TInt count = 0;
       
   366 		TInt err = KErrNone;
       
   367 		if((err = countStmnt.Next() ) == KSqlAtRow)
       
   368 			{
       
   369 			count = countStmnt.ColumnInt(iCountContactsStmnt->ParameterIndex(KSqlCount) );
       
   370 			}
       
   371 		else
       
   372 			{
       
   373 			User::LeaveIfError(err);	
       
   374 			}	
       
   375 
       
   376 		if(count == 0) 
       
   377 			{
       
   378 			User::Leave(KErrNotFound);	
       
   379 			}
       
   380 		CleanupStack::PopAndDestroy(&countStmnt);
       
   381 			
       
   382 		// only insert this if we haven't already seen it
       
   383 		if (itemId != lastId || i == 0)
       
   384 			{
       
   385 			User::LeaveIfError(stmnt.BindInt(KGroupIdIndex, KGroupId) );
       
   386 			User::LeaveIfError(stmnt.BindInt(KMemberIdIndex, itemId) );
       
   387 			User::LeaveIfError(stmnt.Exec() );
       
   388 			User::LeaveIfError(stmnt.Reset() );
       
   389 			}
       
   390 		lastId = itemId;
       
   391 		}
       
   392 
       
   393 	CleanupStack::PopAndDestroy(2, &stmnt); // and sortedList
       
   394 	}
       
   395 
       
   396 
       
   397 /**
       
   398 Deletes information about group for the passed contact item id
       
   399 
       
   400 @param aItemId contact item id
       
   401 @param aLowDiskErrorOccurred out parameter; will be set to ETrue if there was a deletion in 
       
   402 		low disk condition
       
   403 */
       
   404 void CPplGroupsTable::DeleteItemL(TContactItemId aItemId, TBool& aLowDiskErrorOccurred)
       
   405 	{
       
   406 	RSqlStatement stmnt;
       
   407 	CleanupClosePushL(stmnt);
       
   408 	stmnt.PrepareL(iDatabase, iDeleteStmnt->SqlStringL() );
       
   409 
       
   410 	const TInt KGroupIdIndex(KFirstIndex); 			// first parameter in query...	
       
   411 	const TInt KMemberIdIndex(KGroupIdIndex + 1); 	// ...and the second parameter
       
   412 	User::LeaveIfError(stmnt.BindInt(KGroupIdIndex, aItemId) );
       
   413 	User::LeaveIfError(stmnt.BindInt(KMemberIdIndex, aItemId) );
       
   414 	TInt err = stmnt.Exec();
       
   415 	CleanupStack::PopAndDestroy(&stmnt);
       
   416 
       
   417 	if (err == KErrDiskFull)
       
   418 		{
       
   419 		aLowDiskErrorOccurred = ETrue;
       
   420 		}
       
   421 	else
       
   422 		{
       
   423 		User::LeaveIfError(err);
       
   424 		}
       
   425 	}