tzservices/tzserver/Server/Source/tzuserdata.cpp
changeset 0 2e3d3ce01487
child 81 676b6116ca93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tzservices/tzserver/Server/Source/tzuserdata.cpp	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,1022 @@
+// Copyright (c) 2008-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:
+//
+
+#include "tzuserdata.h"
+#include <tz.h>
+#include <f32file.h>
+#include <e32property.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <tzusernames.h>
+#include <tzuserdefineddata.h>
+#endif
+#include "tzidinternal.h"
+
+_LIT(KUserDatabaseName, "c:\\private\\1020383e\\SQLite__tzuserdata.db");
+_LIT(KTzPrivatePath, "c:\\private\\1020383e\\");
+
+// Transaction constants 
+_LIT(KBeginTransaction,"BEGIN TRANSACTION;");
+_LIT(KCommitTransaction,"COMMIT;");
+_LIT(KRollbackTransaction,"ROLLBACK;");
+
+// Tz Rules Table Parameters
+_LIT(KTzRulesTblTzIdParam, ":tzId");
+_LIT(KTzRulesTblRuleTypeParam, ":ruleType");
+_LIT(KTzRulesTblDSTStartTimeParam, ":dstStartTime");
+_LIT(KTzRulesTblDSTStartRefParam, ":dstStartRef"); 
+_LIT(KTzRulesTblDSTEndTimeParam, ":dstEndTime");
+_LIT(KTzRulesTblDSTEndRefParam, ":dstEndRef");
+_LIT(KTzRulesTblOldOffsetParam, ":oldOffset");
+_LIT(KTzRulesTblNewOffsetParam, ":newOffset");
+_LIT(KTzRulesTblMonthParam, ":month");
+_LIT(KTzRulesTblDayParam, ":day");
+_LIT(KTzRulesTblWeekParam, ":week");
+_LIT(KTzRulesTblTimeRefParam, ":timeRef");
+_LIT(KTzRulesTblMinsParam, ":mins");
+
+// Tz Rules Table Index
+_LIT(KTzRulesTblRuleTypeIndex, "ruleType");
+_LIT(KTzRulesTblDSTStartTimeIndex, "dstStartTime");
+_LIT(KTzRulesTblDSTStartRefIndex, "dstStartRef"); 
+_LIT(KTzRulesTblDSTEndTimeIndex, "dstEndTime");
+_LIT(KTzRulesTblDSTEndRefIndex, "dstEndRef");
+_LIT(KTzRulesTblOldOffsetIndex, "oldOffset");
+_LIT(KTzRulesTblNewOffsetIndex, "newOffset");
+_LIT(KTzRulesTblMonthIndex, "month");
+_LIT(KTzRulesTblDayIndex, "day");
+_LIT(KTzRulesTblWeekIndex, "week");
+_LIT(KTzRulesTblTimeRefIndex, "timeRef");
+_LIT(KTzRulesTblMinsIndex, "mins");
+
+// Tz Names Table Parameters
+_LIT(KTzNamesTblTzIdParam, ":tzId");
+_LIT(KTzNamesTblStdNameParam, ":stdName");
+_LIT(KTzNamesTblShortStdNameParam, ":shortStdName");
+_LIT(KTzNamesTblDSTNameParam, ":dstName");
+_LIT(KTzNamesTblShortDSTNameParam, ":shortDstName");
+_LIT(KTzNamesTblCityNameParam, ":cityName");
+_LIT(KTzNamesTblRegionNameParam, ":regionName");
+
+// Tz Names Table Index
+_LIT(KTzNamesTblTzIdIndex, "tzId");
+_LIT(KTzNamesTblStdNameIndex, "stdName");
+_LIT(KTzNamesTblShortStdNameIndex, "shortStdName");
+_LIT(KTzNamesTblDSTNameIndex, "dstName");
+_LIT(KTzNamesTblShortDSTNameIndex, "shortDstName");
+_LIT(KTzNamesTblCityNameIndex, "cityName");
+_LIT(KTzNamesTblRegionNameIndex, "regionName");
+
+// Identifier Table Index
+_LIT(KNextTzIdentifierIndex, "nextTzId");
+
+// InitialStdOffset Table Param
+_LIT(KTzInitialStdOffsetTblTzIdParam, ":tzId");
+_LIT(KTzInitialStdOffsetTblStdInitialOffsetParam, ":initialStdOffset");
+
+// InitialStdOffset Table Index
+_LIT(KTzInitialStdOffsetTblStdInitialOffsetIndex, "initialStdOffset");
+
+// Create statements
+_LIT8 (KTzRulesCreateStmnt, "CREATE TABLE rules (tzId INTEGER NOT NULL, ruleType \
+							 INTEGER, dstStartTime INT64 NOT NULL, dstStartRef INTEGER, \
+							 dstEndTime INT64 NOT NULL, dstEndRef INTEGER, oldOffset \
+							 INTEGER NOT NULL, newOffset INTEGER NOT NULL, month INTEGER, \
+							 day INTEGER, week INTEGER, timeRef INTEGER, mins INTEGER NOT NULL)");
+							 								
+_LIT8 (KTzNamesCreateStmnt, "CREATE TABLE names ( tzId INTEGER NOT NULL PRIMARY \
+							 KEY, stdName CHAR(255), shortStdName CHAR(10), dstName \
+							 CHAR(255), shortDstName CHAR(10), cityName CHAR(255), \
+							 regionName CHAR(255))");
+							
+_LIT8 (KTzIdentifierCreateStmnt, "CREATE TABLE  identifier ( nextTzId INTEGER NOT NULL )");
+
+_LIT8 (KTzInitialStdOffsetCreateStmnt, "CREATE TABLE initialStdOffset (tzId INTEGER NOT NULL, initialStdOffset INTEGER)");
+
+// Insert statements
+_LIT8(KInsertRulesStmnt, "INSERT INTO rules (tzId, ruleType, dstStartTime, dstStartRef, \
+						  dstEndTime, dstEndRef, oldOffset, newOffset, month, day, \
+						  week, timeRef, mins) VALUES (:tzId, :ruleType, :dstStartTime,\
+						  :dstStartRef, :dstEndTime, :dstEndRef, :oldOffset, :newOffset,\
+						  :month, :day, :week, :timeRef, :mins)");
+						  
+_LIT8(KInsertNamesStmnt, "INSERT INTO names(tzId, stdName, shortStdName, dstName, shortDstName,\
+						  cityName, regionName) VALUES(:tzId, :stdName, :shortStdName, :dstName,\
+						  :shortDstName, :cityName, :regionName)");
+						  
+_LIT(KInsertIdentifierStmnt, "INSERT INTO identifier (nextTzId) VALUES (%d)");
+
+_LIT8(KInsertInitialStdOffsetStmnt, "INSERT INTO initialStdOffset (tzId, initialStdOffset) \
+									 VALUES (:tzId, :initialStdOffset)");
+
+//Select statements
+_LIT8(KSelectNextTzIdStmnt, "SELECT nextTzId FROM identifier");
+
+_LIT(KSelectRulesStmnt, "SELECT * FROM rules WHERE tzId = %d");
+
+_LIT(KSelectRulesCountStmnt, "SELECT COUNT(tzId) FROM rules WHERE tzId = %d");
+
+_LIT(KSelectNamesCountStmnt, "SELECT COUNT(tzId) FROM names WHERE tzId = %d");
+
+_LIT(KSelectTzIdCountFromNamesStmnt, "SELECT COUNT(tzId) FROM names WHERE tzId = %d");
+
+_LIT(KSelectNamesStmnt, "SELECT * FROM names WHERE tzId = %d");
+
+_LIT(KSelectTzIdFromNamesStmnt, "SELECT tzId FROM names");
+
+_LIT(KSelectInitialStdOffsetStmnt, "SELECT initialStdOffset FROM initialStdOffset WHERE tzId = %d");
+
+//Update statements
+_LIT (KUpdateIdentifierStmnt, "UPDATE identifier SET nextTzId = :nextTzId");
+
+//Delete statements
+_LIT(KDeleteRulesStmnt, "DELETE FROM rules WHERE tzId = %d");
+
+_LIT(KDeleteNamesStmnt, "DELETE FROM names WHERE tzId = %d");
+
+_LIT(KDeleteInitialStdOffset, "DELETE FROM initialStdOffset WHERE tzId = %d");
+
+const TInt KSqlStringLength = 100;
+const TUint KOutOfBoundsUserId = 0x5000;
+
+CTzUserDataDb* CTzUserDataDb::NewL()
+	{
+	CTzUserDataDb* self = new(ELeave) CTzUserDataDb();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CTzUserDataDb::CTzUserDataDb()
+	{
+	}
+
+CTzUserDataDb::~CTzUserDataDb()
+	{
+	// We don't own the pointers in this array
+	iChangeObservers.Close();
+	iDatabase.Close();
+	}
+
+void CTzUserDataDb::ConstructL()
+	{
+	OpenL();	
+	}
+
+void CTzUserDataDb::Close()
+	{
+	iDatabase.Close();
+	}
+		
+void CTzUserDataDb::OpenL()
+	{
+	RFs fs;
+	CleanupClosePushL(fs);
+	
+	// Open the database
+	TInt ret = iDatabase.Open(KUserDatabaseName());
+	// If the database could not be opened because 
+	// the file was not found in the path provided, create the directory
+	if(ret == KErrNotFound || ret == KErrPathNotFound)
+		{
+		User::LeaveIfError(fs.Connect());
+		ret = fs.MkDir(KTzPrivatePath);
+		// If there are no errors while creating path
+		// or the path already exists, create the database
+		if(ret == KErrNone || ret == KErrAlreadyExists)
+			{
+			CreateL();	
+			}
+		}
+	else
+		{
+		User::LeaveIfError(ret);
+		}
+	CleanupStack::PopAndDestroy(&fs);
+	}
+	
+void CTzUserDataDb::CreateL()
+	{	
+	User::LeaveIfError(iDatabase.Create(KUserDatabaseName()));
+    iDatabase.Close();    
+    CreateSchemaL();
+   	}
+	
+void CTzUserDataDb::CreateSchemaL()
+	{
+	RSqlStatement stmt;
+	CleanupClosePushL(stmt);
+	
+	User::LeaveIfError(iDatabase.Open(KUserDatabaseName()));
+	User::LeaveIfError(stmt.Prepare(iDatabase, KTzRulesCreateStmnt));
+	User::LeaveIfError(stmt.Exec());
+	stmt.Close();
+	
+	User::LeaveIfError(stmt.Prepare(iDatabase, KTzNamesCreateStmnt));
+	User::LeaveIfError(stmt.Exec());
+	stmt.Close();
+
+	User::LeaveIfError(stmt.Prepare(iDatabase, KTzIdentifierCreateStmnt));
+	User::LeaveIfError(stmt.Exec());
+	stmt.Close();
+		
+	TBuf<KSqlStringLength> sqlId;
+	sqlId.Format(KInsertIdentifierStmnt, KUserTzIdMin);
+	User::LeaveIfError(stmt.Prepare(iDatabase, sqlId));
+	User::LeaveIfError(stmt.Exec());
+	stmt.Close();
+	
+	User::LeaveIfError(stmt.Prepare(iDatabase, KTzInitialStdOffsetCreateStmnt));
+	User::LeaveIfError(stmt.Exec());
+	stmt.Close();
+	
+	CleanupStack::PopAndDestroy(&stmt);
+	}
+	
+TInt CTzUserDataDb::CreateTzL(const CTzRules& aRules, const CTzUserNames& aNames)
+	{
+	if(iBackupInProgress || iRestoreInProgress)
+		{
+		User::Leave(KErrLocked);
+		}
+
+	RSqlStatement stmt;
+	CleanupClosePushL(stmt);
+			
+	BeginTransactionL();
+	
+	TInt err = stmt.Prepare(iDatabase, KSelectNextTzIdStmnt);
+	User::LeaveIfError(err);
+	TInt colIndex = stmt.ColumnIndex(KNextTzIdentifierIndex);
+	User::LeaveIfError(colIndex);
+	while((err = stmt.Next()) == KSqlAtRow)
+		{
+		iNextCandidateTzId = stmt.ColumnInt64(colIndex);	
+		}
+	
+	stmt.Close();
+	
+	// Check if the next available user ID is valid
+	if(iNextCandidateTzId == KOutOfBoundsUserId || IsIdInDbL(iNextCandidateTzId))
+		{
+		iNextCandidateTzId = FindUnusedTzIdL();
+		}
+		
+	// If all the user IDs have been used, leave with KErrOverflow	
+	if(iNextCandidateTzId == KOutOfBoundsUserId)
+		{
+		User::Leave(KErrOverflow);		
+		}
+				
+	TUint retId = iNextCandidateTzId;
+	TInt index;	
+	TInt count = aRules.Count();
+	for(TInt i=0; i<count; i++)
+		{
+		TTzRule& rule = const_cast<CTzRules&>(aRules)[i];
+			
+		// Insert a row in the rules
+		User::LeaveIfError(stmt.Prepare(iDatabase, KInsertRulesStmnt()));
+		
+		index = stmt.ParameterIndex(KTzRulesTblTzIdParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt64(index, iNextCandidateTzId));
+		index = stmt.ParameterIndex(KTzRulesTblRuleTypeParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iDayRule));
+		index = stmt.ParameterIndex(KTzRulesTblDSTStartTimeParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt64(index, rule.iFrom.iTime.Int64()));
+		index = stmt.ParameterIndex(KTzRulesTblDSTStartRefParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iFrom.iTimeReference));
+		index = stmt.ParameterIndex(KTzRulesTblDSTEndTimeParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt64(index, rule.iTo.iTime.Int64()));		
+		index = stmt.ParameterIndex(KTzRulesTblDSTEndRefParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iTo.iTimeReference));
+		index = stmt.ParameterIndex(KTzRulesTblOldOffsetParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iOldLocalTimeOffset));
+		index = stmt.ParameterIndex(KTzRulesTblNewOffsetParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iNewLocalTimeOffset));
+		index = stmt.ParameterIndex(KTzRulesTblMonthParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iMonth));
+		index = stmt.ParameterIndex(KTzRulesTblDayParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iDayOfMonth));
+		index = stmt.ParameterIndex(KTzRulesTblWeekParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iDayOfWeek));
+		index = stmt.ParameterIndex(KTzRulesTblTimeRefParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iTimeReference));
+		index = stmt.ParameterIndex(KTzRulesTblMinsParam);
+		User::LeaveIfError(index);
+		User::LeaveIfError(stmt.BindInt(index, rule.iTimeOfChange));
+	
+		TInt ret = stmt.Exec();
+		stmt.Close();
+		
+		if(ret < KErrNone)
+			{
+			User::Leave(ret);
+			}			
+		}
+		
+	// Insert a row in the names
+	User::LeaveIfError(stmt.Prepare(iDatabase, KInsertNamesStmnt()));
+	index = stmt.ParameterIndex(KTzNamesTblTzIdParam);
+	User::LeaveIfError(index);
+	User::LeaveIfError(stmt.BindInt64(index, iNextCandidateTzId));
+	index = stmt.ParameterIndex(KTzNamesTblStdNameParam);
+	User::LeaveIfError(index);
+	User::LeaveIfError(stmt.BindText(index, aNames.StandardName()));
+	index = stmt.ParameterIndex(KTzNamesTblShortStdNameParam);
+	User::LeaveIfError(index);
+	User::LeaveIfError(stmt.BindText(index, aNames.ShortStandardName()));
+	index = stmt.ParameterIndex(KTzNamesTblDSTNameParam);
+	User::LeaveIfError(index);
+	User::LeaveIfError(stmt.BindText(index, aNames.DaylightSaveName()));
+	index = stmt.ParameterIndex(KTzNamesTblShortDSTNameParam);
+	User::LeaveIfError(index);
+	User::LeaveIfError(stmt.BindText(index, aNames.ShortDaylightSaveName()));
+	index = stmt.ParameterIndex(KTzNamesTblCityNameParam);
+	User::LeaveIfError(index);
+	User::LeaveIfError(stmt.BindText(index, aNames.CityName()));
+	index = stmt.ParameterIndex(KTzNamesTblRegionNameParam);
+	User::LeaveIfError(index);
+	User::LeaveIfError(stmt.BindText(index, aNames.RegionName()));
+	TInt ret = stmt.Exec();
+	stmt.Close();
+	
+	if(ret < KErrNone)
+		{
+		User::Leave(ret);
+		}
+
+	User::LeaveIfError(stmt.Prepare(iDatabase, KInsertInitialStdOffsetStmnt));
+	index = stmt.ParameterIndex(KTzInitialStdOffsetTblTzIdParam);
+	User::LeaveIfError(index);
+	User::LeaveIfError(stmt.BindInt(index, iNextCandidateTzId));
+	index = stmt.ParameterIndex(KTzInitialStdOffsetTblStdInitialOffsetParam);
+	User::LeaveIfError(index);
+	TInt initialOffset = aRules.InitialStdTimeOffset();
+	User::LeaveIfError(stmt.BindInt(index, initialOffset));
+	ret = stmt.Exec();
+	stmt.Close();
+	
+	if(ret < KErrNone)
+		{
+		User::Leave(ret);
+		}
+	
+	// Update the next available user ID
+	if(iNextCandidateTzId >= KUserTzIdMax)
+		{
+		iNextCandidateTzId = FindUnusedTzIdL();
+		}
+	else
+		{
+		iNextCandidateTzId++;	
+		}
+	
+	//Insert a row with the new available value of tz id in TZ IdentifierTable
+	User::LeaveIfError(stmt.Prepare(iDatabase, KUpdateIdentifierStmnt));
+	User::LeaveIfError(stmt.BindInt64(0, iNextCandidateTzId));
+	ret = stmt.Exec();
+	stmt.Close();
+	
+	if(ret < KErrNone)
+		{
+		User::Leave(ret);
+		}
+	
+	CommitTransactionL();
+	NotifyTzRulesChange(retId, ETzUserDataCreated);
+	NotifyTzNamesChange(retId, ETzUserDataCreated);
+
+	CleanupStack::PopAndDestroy(&stmt);
+	return retId;	
+	}
+	
+void CTzUserDataDb::ReadTzRulesL(CTzRules& aRules, TUint aTzId)
+	{
+	if(iBackupInProgress || iRestoreInProgress)
+		{
+		User::Leave(KErrLocked);
+		}
+		
+	TSqlScalarFullSelectQuery fullSelectQuery(iDatabase);
+
+	RSqlStatement stmt;
+	CleanupClosePushL(stmt);
+	
+	TTzRule tzRule;	
+
+	TBuf<KSqlStringLength> sqlRules;
+	sqlRules.Format(KSelectRulesCountStmnt, aTzId);
+	TInt count = fullSelectQuery.SelectIntL(sqlRules);
+	if(count == 0)
+		{
+		User::Leave(KErrNotFound);
+		}
+
+	sqlRules.Format(KSelectRulesStmnt, aTzId);
+	TInt err = stmt.Prepare(iDatabase, sqlRules);
+	User::LeaveIfError(err);
+	
+	TInt ruleTypeColIdx = stmt.ColumnIndex(KTzRulesTblRuleTypeIndex);
+	User::LeaveIfError(ruleTypeColIdx);
+	TInt startTimeColIdx = stmt.ColumnIndex(KTzRulesTblDSTStartTimeIndex);
+	User::LeaveIfError(startTimeColIdx);
+	TInt startRefColIdx = stmt.ColumnIndex(KTzRulesTblDSTStartRefIndex);
+	User::LeaveIfError(startRefColIdx);
+	TInt endTimeColIdx = stmt.ColumnIndex(KTzRulesTblDSTEndTimeIndex);
+	User::LeaveIfError(endTimeColIdx);
+	TInt endRefColIdx = stmt.ColumnIndex(KTzRulesTblDSTEndRefIndex);
+	User::LeaveIfError(endRefColIdx);
+	TInt oldOffsetColIdx = stmt.ColumnIndex(KTzRulesTblOldOffsetIndex);
+	User::LeaveIfError(oldOffsetColIdx);
+	TInt newOffsetColIdx = stmt.ColumnIndex(KTzRulesTblNewOffsetIndex);		
+	User::LeaveIfError(newOffsetColIdx);
+	TInt monthColIdx = stmt.ColumnIndex(KTzRulesTblMonthIndex);
+	User::LeaveIfError(monthColIdx);
+	TInt dayColIdx = stmt.ColumnIndex(KTzRulesTblDayIndex);
+	User::LeaveIfError(dayColIdx);
+	TInt weekColIdx = stmt.ColumnIndex(KTzRulesTblWeekIndex);	
+	User::LeaveIfError(weekColIdx);
+	TInt timeRefColIdx = stmt.ColumnIndex(KTzRulesTblTimeRefIndex);
+	User::LeaveIfError(timeRefColIdx);
+	TInt minsColIdx = stmt.ColumnIndex(KTzRulesTblMinsIndex);
+	User::LeaveIfError(minsColIdx);
+	
+	while((err = stmt.Next()) == KSqlAtRow)
+		{			
+		tzRule.iDayRule = static_cast<TTzRuleDay>(stmt.ColumnInt(ruleTypeColIdx));
+		
+		tzRule.iFrom.iTime = stmt.ColumnInt64(startTimeColIdx);
+			
+		tzRule.iFrom.iTimeReference = static_cast<TTzTimeReference>(stmt.ColumnInt(startRefColIdx));
+		
+		tzRule.iTo.iTime = stmt.ColumnInt64(endTimeColIdx); 
+			
+		tzRule.iTo.iTimeReference = static_cast<TTzTimeReference>(stmt.ColumnInt(endRefColIdx));
+		
+		tzRule.iOldLocalTimeOffset = stmt.ColumnInt(oldOffsetColIdx);
+		
+		tzRule.iNewLocalTimeOffset = stmt.ColumnInt(newOffsetColIdx);
+		
+		tzRule.iMonth = static_cast<TMonth>(stmt.ColumnInt(monthColIdx));
+		
+		tzRule.iDayOfMonth = stmt.ColumnInt(dayColIdx);
+		
+		tzRule.iDayOfWeek = stmt.ColumnInt(weekColIdx);
+		
+		tzRule.iTimeReference = static_cast<TTzTimeReference>(stmt.ColumnInt(timeRefColIdx));
+			
+		tzRule.iTimeOfChange = stmt.ColumnInt(minsColIdx);
+		
+		aRules.AddRuleL(tzRule);	
+		}
+	stmt.Close();
+	
+	sqlRules.Format(KSelectInitialStdOffsetStmnt, aTzId);
+	err = stmt.Prepare(iDatabase, sqlRules);
+	User::LeaveIfError(err);
+	TInt stdInitialOffsetIdx = stmt.ColumnIndex(KTzInitialStdOffsetTblStdInitialOffsetIndex);
+	User::LeaveIfError(stdInitialOffsetIdx);	
+	
+	// Fetch the row.
+	User::LeaveIfError(stmt.Next());
+
+	TInt stdInitialOffset = stmt.ColumnInt(stdInitialOffsetIdx);
+	aRules.SetInitialStdTimeOffset(stdInitialOffset);
+
+	// This must be the only row.
+	__ASSERT_ALWAYS(stmt.Next() == KSqlAtEnd, RTz::Panic(RTz::EPanicBadSchema));
+
+	CleanupStack::PopAndDestroy(&stmt);	
+	}
+
+CTzUserNames* CTzUserDataDb::ReadTzNamesL(TUint aTzId)
+	{
+	if(iBackupInProgress || iRestoreInProgress)
+		{
+		User::Leave(KErrLocked);
+		}
+
+	RSqlStatement stmt;
+	CleanupClosePushL(stmt);	
+	
+	TBuf<KSqlStringLength> sqlNames;	
+	TSqlScalarFullSelectQuery fullSelectQuery(iDatabase);
+	sqlNames.Format(KSelectNamesCountStmnt, aTzId);
+	TInt count = fullSelectQuery.SelectIntL(sqlNames);
+	
+	if(count == 0)
+		{
+		User::Leave(KErrNotFound);
+		}
+	
+	sqlNames.Format(KSelectNamesStmnt, aTzId);
+	TInt err = stmt.Prepare(iDatabase, sqlNames);
+	User::LeaveIfError(err);
+		
+	TInt stdNameColIdx = stmt.ColumnIndex(KTzNamesTblStdNameIndex);
+	User::LeaveIfError(stdNameColIdx);
+
+	TInt shortStdNameColIdx = stmt.ColumnIndex(KTzNamesTblShortStdNameIndex);
+	User::LeaveIfError(shortStdNameColIdx);
+		
+	TInt dstNameColIdx = stmt.ColumnIndex(KTzNamesTblDSTNameIndex);
+	User::LeaveIfError(dstNameColIdx);
+		
+	TInt shortDstNameColIdx = stmt.ColumnIndex(KTzNamesTblShortDSTNameIndex);
+	User::LeaveIfError(shortDstNameColIdx);
+		
+	TInt cityNameColIdx = stmt.ColumnIndex(KTzNamesTblCityNameIndex);
+	User::LeaveIfError(cityNameColIdx);
+	
+   	TInt regionNameColIdx = stmt.ColumnIndex(KTzNamesTblRegionNameIndex);
+	User::LeaveIfError(regionNameColIdx);
+	
+   	CTzUserNames* userNames = NULL;
+   	
+	// Fetch the row.
+   	User::LeaveIfError(stmt.Next());
+
+	TPtrC standardName;
+	standardName.Set(stmt.ColumnTextL(stdNameColIdx));	
+
+	TPtrC shortStandardName;
+	shortStandardName.Set(stmt.ColumnTextL(shortStdNameColIdx));
+
+	TPtrC daylightName;
+	daylightName.Set(stmt.ColumnTextL(dstNameColIdx));
+
+	TPtrC shortDaylightName; 
+	shortDaylightName.Set(stmt.ColumnTextL(shortDstNameColIdx));
+
+	TPtrC cityName;
+	cityName.Set(stmt.ColumnTextL(cityNameColIdx));
+
+	TPtrC regionName;
+	regionName.Set(stmt.ColumnTextL(regionNameColIdx));
+
+	userNames = CTzUserNames::NewL(standardName, shortStandardName,
+		daylightName, shortDaylightName, cityName, regionName);
+
+	// This must be the only row.
+	__ASSERT_ALWAYS(stmt.Next() == KSqlAtEnd, RTz::Panic(RTz::EPanicBadSchema));
+
+	CleanupStack::PopAndDestroy(&stmt);
+
+	return userNames;
+	}
+	
+void CTzUserDataDb::ReadTzIdsL(RArray<TUint32>& aTzIds)
+	{
+	if(iBackupInProgress || iRestoreInProgress )
+		{
+		User::Leave(KErrLocked);
+		}
+	
+	RSqlStatement stmt;
+	CleanupClosePushL(stmt);
+
+	TBuf<KSqlStringLength> sqlRule;
+	sqlRule.Format(KSelectTzIdFromNamesStmnt);
+	TInt err = stmt.Prepare(iDatabase, sqlRule);
+	User::LeaveIfError(err);
+		
+	while((err = stmt.Next()) == KSqlAtRow)
+		{
+		TInt col = stmt.ColumnIndex(KTzNamesTblTzIdIndex);
+		User::LeaveIfError(col);
+		TUint id = stmt.ColumnInt64(col);
+		aTzIds.AppendL(id);
+		}
+
+	CleanupStack::PopAndDestroy(&stmt);
+	}
+	
+void CTzUserDataDb::UpdateTzL(TUint aTzId, const CTzRules& aTzRules, const CTzUserNames& aTzNames)
+	{	
+	if(iBackupInProgress || iRestoreInProgress)
+		{
+		User::Leave(KErrLocked);
+		} 
+		
+	RSqlStatement stmt;
+	CleanupClosePushL(stmt);
+	
+	BeginTransactionL();	
+					
+	TBuf<KSqlStringLength> sqlRules;
+	sqlRules.Format(KDeleteRulesStmnt, aTzId);
+	TInt ret = stmt.Prepare(iDatabase, sqlRules);
+	if(ret == KErrNone)
+		{
+		ret = stmt.Exec();
+		if(ret < KErrNone)
+			{
+			User::Leave(ret);
+			}
+		}
+	stmt.Close();
+	
+	const TInt count = aTzRules.Count();
+	for(TInt i=0; i<count; i++)
+		{
+		TTzRule& rule = const_cast<CTzRules&>(aTzRules)[i];
+
+		User::LeaveIfError(stmt.Prepare(iDatabase, KInsertRulesStmnt));
+
+		TInt paramIdx = stmt.ParameterIndex(KTzRulesTblTzIdParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt64(paramIdx, aTzId));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblRuleTypeParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iDayRule));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblDSTStartTimeParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt64(paramIdx, rule.iFrom.iTime.Int64()));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblDSTStartRefParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iFrom.iTimeReference));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblDSTEndTimeParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt64(paramIdx, rule.iTo.iTime.Int64()));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblDSTEndRefParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iTo.iTimeReference));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblOldOffsetParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iOldLocalTimeOffset));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblNewOffsetParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iNewLocalTimeOffset));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblMonthParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iMonth));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblDayParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iDayOfMonth));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblWeekParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iDayOfWeek));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblTimeRefParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iTimeReference));
+
+		paramIdx = stmt.ParameterIndex(KTzRulesTblMinsParam);
+		User::LeaveIfError(paramIdx);
+		User::LeaveIfError(stmt.BindInt(paramIdx, rule.iTimeOfChange));
+
+		ret = stmt.Exec();
+		stmt.Close();
+		if(ret < KErrNone)
+			{
+			User::Leave(ret);
+			}
+		}
+	
+	TBuf<KSqlStringLength> sqlInitialOffset;
+	sqlInitialOffset.Format(KDeleteInitialStdOffset, aTzId);
+	ret = stmt.Prepare(iDatabase, sqlInitialOffset);
+	if(ret == KErrNone)
+		{
+		ret = stmt.Exec();	
+		stmt.Close();
+		if(ret < KErrNone)
+			{
+			User::Leave(ret);
+			}
+		}
+
+	User::LeaveIfError(stmt.Prepare(iDatabase, KInsertInitialStdOffsetStmnt));
+
+	TInt paramIdx = stmt.ParameterIndex(KTzInitialStdOffsetTblTzIdParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindInt64(paramIdx, aTzId));
+
+	TInt initialOffset = aTzRules.InitialStdTimeOffset();
+
+	paramIdx = stmt.ParameterIndex(KTzInitialStdOffsetTblStdInitialOffsetParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindInt64(paramIdx, initialOffset));
+
+	ret = stmt.Exec();
+	stmt.Close();
+	if(ret < KErrNone)
+		{
+		User::Leave(ret);
+		}
+	
+	TBuf<KSqlStringLength> sqlNames; 
+	sqlNames.Format(KDeleteNamesStmnt, aTzId);
+	ret = stmt.Prepare(iDatabase, sqlNames);
+	if(ret == KErrNone)
+		{
+		ret = stmt.Exec();	
+		if(ret < KErrNone)
+			{
+			User::Leave(ret);
+			}
+		}
+	stmt.Close();
+	
+	// Insert a row in the names
+	User::LeaveIfError(stmt.Prepare(iDatabase, KInsertNamesStmnt));
+
+	paramIdx = stmt.ParameterIndex(KTzNamesTblTzIdParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindInt64(paramIdx, aTzId));
+
+	paramIdx = stmt.ParameterIndex(KTzNamesTblStdNameParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindText(paramIdx, aTzNames.StandardName()));
+
+	paramIdx = stmt.ParameterIndex(KTzNamesTblShortStdNameParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindText(paramIdx, aTzNames.ShortStandardName()));
+
+	paramIdx = stmt.ParameterIndex(KTzNamesTblDSTNameParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindText(paramIdx, aTzNames.DaylightSaveName()));
+
+	paramIdx = stmt.ParameterIndex(KTzNamesTblShortDSTNameParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindText(paramIdx, aTzNames.ShortDaylightSaveName()));
+
+	paramIdx = stmt.ParameterIndex(KTzNamesTblCityNameParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindText(paramIdx, aTzNames.CityName()));
+
+	paramIdx = stmt.ParameterIndex(KTzNamesTblRegionNameParam);
+	User::LeaveIfError(paramIdx);
+	User::LeaveIfError(stmt.BindText(paramIdx, aTzNames.RegionName()));
+
+	ret = stmt.Exec();
+	stmt.Close();
+	if(ret < KErrNone)
+		{
+		User::Leave(ret);
+		}
+	
+	CommitTransactionL();
+
+	NotifyTzRulesChange(aTzId, ETzUserDataUpdated);
+	NotifyTzNamesChange(aTzId, ETzUserDataUpdated);
+	
+	CleanupStack::PopAndDestroy(&stmt);	
+	}
+    
+/**
+Delete the time zone rule and name from the database that matches aTzId
+*/
+void CTzUserDataDb::DeleteTzL(TUint aTzId)
+	{
+	if(iBackupInProgress || iRestoreInProgress)
+		{
+		User::Leave(KErrLocked);
+		}
+		
+	RSqlStatement stmt;
+	CleanupClosePushL(stmt);
+	
+	BeginTransactionL();
+	
+	TInt ret;		
+	TBuf<KSqlStringLength> sqlRules;
+	sqlRules.Format(KDeleteRulesStmnt, aTzId);
+	User::LeaveIfError(stmt.Prepare(iDatabase, sqlRules));
+	ret = stmt.Exec();
+	stmt.Close();
+	if(ret < KErrNone)
+		{
+		User::Leave(ret);
+		}
+	
+	TBuf<KSqlStringLength> sqlInitialOffset;
+	sqlInitialOffset.Format(KDeleteInitialStdOffset, aTzId);
+	ret = stmt.Prepare(iDatabase, sqlInitialOffset);
+	if(ret == KErrNone)
+		{
+		ret = stmt.Exec();	
+		stmt.Close();
+		if(ret < KErrNone)
+			{
+			User::Leave(ret);
+			}
+		}
+		
+	TBuf<KSqlStringLength> sqlNames;
+	sqlNames.Format(KDeleteNamesStmnt, aTzId);
+	User::LeaveIfError(stmt.Prepare(iDatabase, sqlNames));
+	ret = stmt.Exec();
+	stmt.Close();
+		
+	if(ret < KErrNone)
+		{
+		User::Leave(ret);
+		}
+	
+	CommitTransactionL();
+
+	NotifyTzRulesChange(aTzId, ETzUserDataDeleted);
+	NotifyTzNamesChange(aTzId, ETzUserDataDeleted);	
+	
+	CleanupStack::PopAndDestroy(&stmt);
+	}
+	
+void CTzUserDataDb::CleanupDatabaseRollback(TAny *aDatabase)
+	{
+	ASSERT(aDatabase);
+	CTzUserDataDb* db = static_cast<CTzUserDataDb*>(aDatabase);
+	db->RollbackTransaction();
+	}
+	
+/**
+Begin a new transation
+*/
+void CTzUserDataDb::BeginTransactionL()
+	{
+	User::LeaveIfError(iDatabase.Exec(KBeginTransaction));
+	CleanupStack::PushL(TCleanupItem(CleanupDatabaseRollback, this));
+	}
+	
+/**
+Commit the changes made since the start of a transaction
+*/
+void CTzUserDataDb::CommitTransactionL()
+	{
+	User::LeaveIfError(iDatabase.Exec(KCommitTransaction));
+	CleanupStack::Pop(); //CleanupDatabaseRollback
+	}
+	
+/**
+Rollback changes since the start of the transaction
+*/
+void CTzUserDataDb::RollbackTransaction()
+	{
+	iDatabase.Exec(KRollbackTransaction);
+	}
+	
+// Notification operations.
+void CTzUserDataDb::NotifyTzRulesChange(TUint aTzId, TTzUserDataChangeOp aChangeOp)
+	{
+	TTzUserDataChange change;
+	change.iTzId = aTzId;
+	change.iOperation = aChangeOp;
+		
+	TInt j = 0;
+	TInt jEnd = iChangeObservers.Count();
+	while (j < jEnd)
+		{
+		iChangeObservers[j]->NotifyUserTzRulesChange(change);
+		++j;
+		}
+	
+	//Publish ETzRulesChange property to the subscribed clients
+	NTzUpdate::TTzRulesChange rulesChange;
+	rulesChange.iUTCTimeOfRulesChange.UniversalTime();
+	TPckgBuf<NTzUpdate::TTzRulesChange> bufRules(rulesChange);
+	RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzRulesChange, bufRules);
+	}
+    
+void CTzUserDataDb::NotifyTzNamesChange(TUint aTzId, TTzUserDataChangeOp aChangeOp)
+	{
+	TTzUserDataChange change;
+	change.iTzId = aTzId;
+	change.iOperation = aChangeOp;
+	
+	TInt j = 0;
+	TInt jEnd = iChangeObservers.Count();
+	while (j < jEnd)
+		{
+		iChangeObservers[j]->NotifyUserTzNamesChange(change);
+		++j;
+		}
+	
+	//Publish ETzNamesChange property to the subscribed clients
+	NTzUpdate::TTzNamesChange namesChange;
+	namesChange.iUTCTimeOfNamesChange.UniversalTime();
+	TPckgBuf<NTzUpdate::TTzNamesChange> bufNames(namesChange);
+	RProperty::Set(NTzUpdate::KPropertyCategory, NTzUpdate::ETzNamesChange, bufNames);	
+	}
+
+ // Backup and restore operations
+void CTzUserDataDb::BackupBeginningL()
+	{
+	Close();
+	iBackupInProgress = ETrue;
+	}
+
+void CTzUserDataDb::BackupCompletedL()
+	{
+	OpenL();
+	iBackupInProgress = EFalse;
+	}
+
+void CTzUserDataDb::RestoreBeginningL()
+	{
+	Close();
+	iRestoreInProgress = ETrue;
+	}
+
+void CTzUserDataDb::RestoreCompletedL()
+	{
+	OpenL();		
+	iRestoreInProgress = EFalse;
+	}
+
+void CTzUserDataDb::AddObserverL(MTzUserDataChangeObserver* aChangeObs)
+	{
+	User::LeaveIfError(iChangeObservers.Append(aChangeObs));
+	}
+
+void CTzUserDataDb::RemoveObserver(MTzUserDataChangeObserver* aChangeObs)
+	{
+	TInt j = 0;
+	TInt jEnd = iChangeObservers.Count();
+	while (j < jEnd)
+		{
+		if (iChangeObservers[j] == aChangeObs)
+			{
+			iChangeObservers.Remove(j);
+			break;
+			}
+		++j;
+		}
+	}
+/**
+Checks if aTzId exists in the user timezone database
+*/
+TBool CTzUserDataDb::IsIdInDbL(TUint aTzId)
+	{
+	TBuf<KSqlStringLength> sqlNames;
+	TSqlScalarFullSelectQuery fullSelectQuery(iDatabase);
+	sqlNames.Format(KSelectTzIdCountFromNamesStmnt, aTzId);
+	
+	TInt count = fullSelectQuery.SelectIntL(sqlNames);
+	if(count == 0)
+		{
+		return EFalse;
+		}		
+	return ETrue;
+	}
+/**
+Find the next unused id in the database. If all ids have been used
+KOutOfBoundsUserId will be returned
+*/
+TUint32 CTzUserDataDb::FindUnusedTzIdL()
+	{
+	RArray<TUint32> ids;
+	CleanupClosePushL(ids);
+	ReadTzIdsL(ids);
+	const TInt count = ids.Count();
+	TUint foundId = KOutOfBoundsUserId;
+	if(count > 0)
+		{
+		ids.SortSigned();
+	
+		for(TInt i=0; i<count-1; i++)
+			{
+			if(ids[i]+1 != ids[i+1])
+				{
+				foundId = ids[i]+1;
+				break;
+				}
+			}
+		}
+	CleanupStack::PopAndDestroy(&ids);
+	return foundId;
+	}