diff -r 000000000000 -r 08ec8eefde2f persistentstorage/sql/SRC/Server/SqlSrvMain.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/sql/SRC/Server/SqlSrvMain.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,528 @@ +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include "SqlSrvMain.h" //CSqlServer +#include "SqlSrvStartup.h" //SqlSrvVersion() +#include "SqlSrvSession.h" //CSqlSrvSession +#include "SqlSrvDbSysSettings.h"//TSqlDbSysSettings +#include "SqlSrvStatementUtil.h" +#include "SqlSrvStatement.h" +#include "sqlite3.h" //sqlite3_enable_shared_cache() +#include "SqliteSymbian.h" //sqlite3SymbianLibInit() +#include "SqlCompact.h" +#include "SqlCompactConn.h" +#include "SqlSrvResourceProfiler.h" +#include "UTraceSql.h" +#ifdef _DEBUG +#include +#endif + +static CSqlServer* TheServer = NULL;//The single CSqlServer instance + +_LIT(KMatchAllDbFiles, "*"); +_LIT(KDefaultICollationDllName, ""); + +//Constants for enabling/disabling the shared cache +enum TSharedCacheState + { + EDisableSharedCache = 0, + EEnableSharedCache = 1 + }; + +#ifdef SYSLIBS_TEST + //The "lookaside" optimisation is disabled if SYSLIBS_TEST macro is defined. + //According to the SQLite authors recommendations, the OOM testing should be performed without this optimisation. + const TInt KSqliteLookAsideCellSize = 0; + const TInt KSqliteLookAsideCellCount = 0; +#else + //SQLite, "fixed heap cell size" constants + //SQLite will preallocate KSqliteLookAsideCellSize * KSqliteLookAsideCellCount bytes from the heap and + //use the allocated block for all allocation requests with size <= KSqliteLookAsideCellSize. + //The malloc()/free() request time is constant, if the cell is retrieved/returned from/to the "fixed cell size" block. + const TInt KSqliteLookAsideCellSize = 128; + const TInt KSqliteLookAsideCellCount = 512; +#endif + +//Local function, used for comparing TSqlSecurityPair objects. +//The keys are expected to be UTF8 encoded, zero-terminated. +// +//The function will panic with panic code 7 in _DEBUG mode if the key part of aLeft or +//aRight argument is NULL. +static TInt Compare(const TSqlSecurityPair& aLeft, const TSqlSecurityPair& aRight) + { + __SQLASSERT(aLeft.iKey != NULL && aRight.iKey != NULL, ESqlPanicInternalError); + return ::CompareNoCase8(TPtrC8(aLeft.iKey), TPtrC8(aRight.iKey)); + } + +/** +Returns a reference to the sql server instance. + +@return A reference to the sql server instance. + +@panic SqlDb 2 If the sql server instance is NULL. + +@internalComponent +*/ +CSqlServer& SqlServer(void) + { + __SQLASSERT_ALWAYS(TheServer != NULL, ESqlPanicInvalidObj); + return *TheServer; + } + +/** +Creates new CSqlServer instance. +The created instance will be pushed in the cleanup stack. + +@return A pointer to the created CSqlServer instance. + +@leave KErrNoMemory, an out of memory condition has occured; +*/ +CSqlServer* CSqlServer::NewLC() + { + CSqlServer* self = new (ELeave) CSqlServer; + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +/** +Frees owned by CSqlServer memory and other resources. +*/ +CSqlServer::~CSqlServer() + { + delete iCompactor; + delete iBackupClient; + iDriveSpaceCol.ResetAndDestroy(); + sqlite3_soft_heap_limit(0);//Set to 0 the soft heap limit + iSecurityMap.Close(); + (void)sqlite3_enable_shared_cache(static_cast (EDisableSharedCache)); + iFlatBuf.Close(); + User::Free(iBuf); + delete iDbConfigFiles; + sqlite3SymbianLibFinalize(); + TheServer = NULL; + SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KSqlSrvClose)); + SQLPROFILER_SERVER_STOP(); + } + +/** +@param aMinLen Requested minimal byte size of the flat buffer + +@return A reference to the server's general purpose flat bufer. The buffer cannot keep a state between calls. +*/ +RSqlBufFlat& CSqlServer::GetFlatBufL(TInt aMinLen) + { + __SQLASSERT(aMinLen >= 0, ESqlPanicBadArgument); + __SQLLEAVE_IF_ERROR(iFlatBuf.ReAlloc(aMinLen)); + SQLPROFILER_REPORT_ALLOC(iFlatBuf.MaxSize()); + return iFlatBuf; + } + +/** +Returns a 8-bit descriptor's reference to the server's general purpose buffer. +Note that the function may reallocate the buffer if the buffer length is smaller than the requested minimal length. + +@param aMinLen Requested minimal 8-bit character length of the buffer + +@return TDes8 reference to the server's general purpose bufer. The buffer cannot keep a state between calls. +*/ +TDes8& CSqlServer::GetBuf8L(TInt aMinLen) + { + __SQLASSERT(aMinLen >= 0, ESqlPanicBadArgument); +#ifdef _DEBUG +TInt maxBufLen = iBufPtr8.MaxLength(); +maxBufLen = maxBufLen; +#endif + if(iBufPtr8.MaxLength() < aMinLen) + { + __SQLLEAVE_IF_ERROR(ReAllocBuf(aMinLen)); + } + SQLPROFILER_REPORT_ALLOC(iBufPtr8.MaxLength()); + return iBufPtr8; + } + +/** +Returns a 16-bit descriptor's reference to the server's general purpose buffer. +Note that the function may reallocate the buffer if the buffer length is smaller than the requested minimal length. + +@param aMinLen Requested minimal 16-bit character length of the buffer + +@return TDes16 reference to the server's general purpose bufer. The buffer cannot keep a state between calls. +*/ +TDes16& CSqlServer::GetBuf16L(TInt aMinLen) + { + __SQLASSERT(aMinLen >= 0, ESqlPanicBadArgument); +#ifdef _DEBUG +TInt maxBufLen = iBufPtr16.MaxLength(); +maxBufLen = maxBufLen; +#endif + if(iBufPtr16.MaxLength() < aMinLen) + { + __SQLLEAVE_IF_ERROR(ReAllocBuf(aMinLen * sizeof(TUint16))); + } + SQLPROFILER_REPORT_ALLOC(iBufPtr16.MaxLength()); + return iBufPtr16; + } + +/** +If iFlatBuf or iBuf allocated memory is more than KBufLimit bytes, +then that buffer will be reallocated down to KBufLimit size. +*/ +void CSqlServer::MinimizeBuffers() + { + iFlatBuf.ResetAndMinimize(); +#ifdef _DEBUG + const TInt KBufLimit = 64; + const TUint8* oldBuf = iBuf; +#else + const TInt KBufLimit = 8 * 1024; +#endif + if(iBufPtr8.MaxSize() > KBufLimit) + { + (void)ReAllocBuf(KBufLimit); + __SQLASSERT(oldBuf == iBuf, ESqlPanicInternalError); + } + } + +/** +Reallocates iBuf. iBuf content is not preserved. +Sets iBufPtr8 and iBufPtr16 to point to iBuf. + +@param aNewBufSize The new buffer size in bytes + +@return KErrNoMemory, an out of memory condition has occurred; + KErrNone, the operation has completed successfully; +*/ +TInt CSqlServer::ReAllocBuf(TInt aNewBufSize) + { + __SQLASSERT(aNewBufSize >= 0, ESqlPanicBadArgument); +#ifdef _DEBUG + const TInt KMinBufSize = 8; +#else + const TInt KMinBufSize = 2 * 1024; +#endif + const TInt KNewBufSize = Max(aNewBufSize, KMinBufSize); + TUint8* newBuf = static_cast (User::ReAlloc(iBuf, KNewBufSize)); + if(newBuf) + { + iBuf = newBuf; + iBufPtr8.Set(iBuf, 0, KNewBufSize); + iBufPtr16.Set(reinterpret_cast (iBuf), 0, (TUint)KNewBufSize / sizeof(TUint16)); + return KErrNone; + } + else + {//The reallocation has failed, iBuf - not changed + iBufPtr8.Zero(); + iBufPtr16.Zero(); + return KErrNoMemory; + } + } + +/** +Creates new CSqlSrvSession instance. + +@return A pointer to the created CSqlSrvSession instance. + +@leave KErrNoMemory, an out of memory condition has occured; + KErrNotSupported, the client side library version differs from the server version. + +@see CSqlSrvSession +*/ +CSession2* CSqlServer::NewSessionL(const TVersion &aVersion, const RMessage2&) const + { + if(!User::QueryVersionSupported(::SqlSrvVersion(), aVersion)) + { + User::Leave(KErrNotSupported); + } + CSqlSrvSession* sess = CSqlSrvSession::NewL(); + return sess; + } + +/** +CSqlServer's active object priority. + +@internalComponent +*/ +const TInt KSqlServerPriority = CActive::EPriorityStandard; + +/** +Initializes CSqlServer data members with default values. +*/ +CSqlServer::CSqlServer() : + CServer2(KSqlServerPriority, ESharableSessions), + iSecurityMap(TSqlSecurityLinearOrder(&Compare), TSqlSecurityDestructor()), + iBufPtr8(0, 0), + iBufPtr16(0, 0) + { + } + +/** +Initializes CSqlServer instance: + - starts the server; + - opens sqlite library; + - initializes the file session instance; + - creates server's private directory on the system drive; + - enables sqlite shared cache; + +@leave KErrNoMemory, an out of memory condition has occured; + Note that the function may also leave with some other database specific + errors categorised as ESqlDbError. +*/ +void CSqlServer::ConstructL() + { + StartL(KSqlSrvName); +#ifdef _SQLPROFILER + TheSqlSrvStartTime.UniversalTime(); + SQLPROFILER_SERVER_START(); +#endif + //Configure the SQLite library + __SQLLEAVE_IF_ERROR(sqlite3_config(SQLITE_CONFIG_LOOKASIDE, KSqliteLookAsideCellSize, KSqliteLookAsideCellCount)); + //Open SQLITE library - this must be the first call after StartL() (os_symbian.cpp, "TheAllocator" initialization rellated). + __SQLLEAVE_IF_ERROR(sqlite3SymbianLibInit()); + //Create buffers + __SQLLEAVE_IF_ERROR(iFlatBuf.SetCount(0)); + //Get collation dll name + GetCollationDllNameL(); + //Get the system drive. + TInt sysDrive = static_cast(RFs::GetSystemDrive()); + //Get the server private data path. + RFs& fs = sqlite3SymbianFs(); + TFileName serverPrivatePath; + __SQLLEAVE_IF_ERROR(fs.PrivatePath(serverPrivatePath)); + //Load config file parameter values (if config file exists) and initialize iFileData. + TParse parse; + __SQLLEAVE_IF_ERROR(parse.Set(KSqlSrvDefaultConfigFile, &serverPrivatePath, NULL)); + //Store the names of any existing database config files in memory + CacheDbConfigFileNamesL(fs, serverPrivatePath); + //Initialise the file data object + iFileData.InitL(fs, TDriveUnit(sysDrive).Name(), serverPrivatePath, parse.FullName(), iDbConfigFiles); + + //Set the soft heap limit (iFileData.ConfigParams() returns now a reference to the config file params, including the soft heap limit, if set) + const TSqlSrvConfigParams& configParams = iFileData.ConfigParams(); + if(configParams.iSoftHeapLimitKb > 0) + { + __SQLASSERT(configParams.iSoftHeapLimitKb >= TSqlSrvConfigParams::KMinSoftHeapLimitKb && + configParams.iSoftHeapLimitKb <= TSqlSrvConfigParams::KMaxSoftHeapLimitKb, ESqlPanicInternalError); + sqlite3_soft_heap_limit(configParams.iSoftHeapLimitKb * 1024); + } + //Enable shared cache + (void)sqlite3SymbianLastOsError();//clear last OS error + TInt err = sqlite3_enable_shared_cache(static_cast (EEnableSharedCache)); + __SQLLEAVE_IF_ERROR(::Sql2OsErrCode(err, sqlite3SymbianLastOsError())); + //Create an empty "drive space" collection + iDriveSpaceCol.Create(fs); + // Create the BUR instance + iBackupClient=CSqlBackupClient::NewL(this); + //Compactor + iCompactor = CSqlCompactor::NewL(&SqlCreateCompactConnL, KSqlCompactStepIntervalMs); +#ifdef _DEBUG + /* + The following statements exist to prevent the failure of the resource allocation + checking for debug mode. + They allocate some memory when the server object is constructed so avoid these memory + allocations during debug mode. + */ +const TInt KAnyNumber = 0xAA55; +const TInt KGreatSize = 1024; + char tmp[32]; + sprintf(tmp, "%04X", KAnyNumber); + __SQLLEAVE_IF_ERROR(ReAllocBuf(KGreatSize)); +#endif + } + +/** +Retrieves in iCollationDllName current(default) collation dll name. +see TExtendedLocale +*/ +void CSqlServer::GetCollationDllNameL() + { + TExtendedLocale extdlocale; + extdlocale.LoadSystemSettings(); + TFileName fname; + TParse fileName; + TInt err = extdlocale.GetLocaleDllName(ELocaleCollateSetting, fname); + if(err!= KErrNone) + iCollationDllName = KDefaultICollationDllName; + else + { + //only get the file name + extension + fileName.Set(fname, NULL, NULL); + iCollationDllName = fileName.NameAndExt(); + } + } +/** +Finds and caches the name of each database configuration file +that exists in the server's private data cage on the Z: drive +*/ +void CSqlServer::CacheDbConfigFileNamesL(RFs& aFs, const TDesC& aServerPrivatePath) + { + //Create an in-memory array holding the names of the database config files, if any exist + TParse parseDbConfig; + __SQLLEAVE_IF_ERROR(parseDbConfig.Set(KSqlSrvDbConfigFileFormat, &aServerPrivatePath, NULL)); + TFileName configFilePath(parseDbConfig.FullName()); // get 'drive:\private path\cfg*' search string + CDir* entryList = 0; // memory will be allocated for this in GetDir() + TInt err = aFs.GetDir(configFilePath, KEntryAttNormal, ESortByName, entryList); + CleanupStack::PushL(entryList); + if(!err) + { + if(entryList && (entryList->Count() > 0)) + { + iDbConfigFiles = CDbConfigFiles::NewL(*entryList); + } + } + else + { + __SQLLOG_ERR(_L("SQLLOG: CSqlServer::CacheDbConfigFileNamesL() - GetDir() failed with error code %d"), err); + } + CleanupStack::PopAndDestroy(); // entryList + } + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// MSqlPolicyInspector implementation /////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +Implements MSqlPolicyInspector::Check() method. + +@see MSqlPolicyInspector +@see MSqlPolicyInspector::Check() +*/ +TBool CSqlServer::Check(const TSecurityPolicy& aPolicy) const + { + return aPolicy.CheckPolicy(CServer2::Message()); + } + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////// MSqlSrvBurInterface implementation ////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** +Implements MSqlSrvBurInterface::Fs(). + +@return A reference to the file session instance. +*/ +RFs& CSqlServer::Fs() + { + return iFileData.Fs(); + } + +/** +Implements MSqlSrvBurInterface::GetBackupListL(). +Retrieves in aFileList parameter a list of secure database names (full database paths actually) +which security UID matches aUid parameter. +Database files on ROM drive(s) won't be put in aFileList. + +@param aUid Database security UID. +@param aFileList An output parameter. If the function completes successfully, then aFileList will be filled + with all secure database file names which security UID matches aUid parameter. + Database files on ROM drive(s) won't be put in aFileList. + +@leave KErrNoMemory, an out of memory condition has occured; + Note that the function may leave also with some other database specific or OS specific + error codes. +*/ +void CSqlServer::GetBackUpListL(TSecureId aUid, RArray& aFileList) + { + TFindFile findFile(iFileData.Fs()); + CDir* fileNameCol = NULL; + TUidName uidName = (static_cast (aUid)).Name(); + TBuf fileNameMask(uidName); + fileNameMask.Append(KMatchAllDbFiles); + //Find all files which name is matching "[aUid]*" pattern. + TInt err = findFile.FindWildByDir(fileNameMask, iFileData.PrivatePath(), fileNameCol); + if(err == KErrNone) + { + //The first set of files, which name is matching "[aUid]*" pattern, is ready. + do + { + __SQLASSERT(fileNameCol != NULL, ESqlPanicInternalError); + CleanupStack::PushL(fileNameCol); + const TDesC& file = findFile.File();//"file" variable contains the drive and the path. the file name in "file" is invalid in this case. + //Check that the drive, where the database files are, is not ROM drive + TParse parse; + (void)parse.Set(file, NULL, NULL);//this call can't file, the file name comes from findFile call. + TPtrC driveName = parse.Drive(); + __SQLASSERT(driveName.Length() > 0, ESqlPanicInternalError); + TInt driveNumber = -1; + __SQLLEAVE_IF_ERROR(RFs::CharToDrive(driveName[0], driveNumber)); + TDriveInfo driveInfo; + __SQLLEAVE_IF_ERROR(iFileData.Fs().Drive(driveInfo, static_cast (driveNumber))); + //If current drive is not ROM drive then process the files + if(!(driveInfo.iDriveAtt & KDriveAttRom)) + { + TInt cnt = fileNameCol->Count(); + //For each found database file, which name is matching "[aUid]*" pattern, do: + for(TInt i=0;i