--- /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 <hal.h>
+#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 <stdio.h>
+#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 <TInt> (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 <TUint8*> (User::ReAlloc(iBuf, KNewBufSize));
+ if(newBuf)
+ {
+ iBuf = newBuf;
+ iBufPtr8.Set(iBuf, 0, KNewBufSize);
+ iBufPtr16.Set(reinterpret_cast <TUint16*> (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<TInt>(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 <TInt> (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<TParse>& aFileList)
+ {
+ TFindFile findFile(iFileData.Fs());
+ CDir* fileNameCol = NULL;
+ TUidName uidName = (static_cast <TUid> (aUid)).Name();
+ TBuf<KMaxUidName + sizeof(KMatchAllDbFiles)> 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 <TDriveNumber> (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<cnt;++i)
+ {
+ const ::TEntry& entry = (*fileNameCol)[i];
+ if(!entry.IsDir())
+ {
+ (void)parse.Set(entry.iName, &file, NULL);//"parse" variable now contains the full file path
+ __SQLLEAVE_IF_ERROR(aFileList.Append(parse));
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(fileNameCol);
+ fileNameCol = NULL;
+ } while((err = findFile.FindWild(fileNameCol)) == KErrNone);//Get the next set of files
+ }//end of "if(err == KErrNone)"
+ __SQLASSERT(!fileNameCol, ESqlPanicInternalError);
+ if(err != KErrNotFound && err != KErrNone)
+ {
+ __SQLLEAVE(err);
+ }
+ }
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////// SQL server startup //////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//Run the SQL server
+static void RunServerL()
+ {
+ // naming the server thread after the server helps to debug panics
+ User::LeaveIfError(User::RenameThread(KSqlSrvName));
+
+ // create and install the active scheduler we need
+ CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
+ CleanupStack::PushL(scheduler);
+ CActiveScheduler::Install(scheduler);
+ SYMBIAN_TRACE_SQL_EVENTS_ONLY(UTF::Printf(UTF::TTraceContext(UTF::EInternals), KSqlSrvStart));
+ TheServer = CSqlServer::NewLC();
+ RProcess::Rendezvous(KErrNone);
+ CActiveScheduler::Start();
+
+ CleanupStack::PopAndDestroy(2, scheduler);//CSqlServer, scheduler
+ }
+
+// SQL server process entry point
+TInt E32Main()
+ {
+ __UHEAP_MARK;
+
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ TInt err = KErrNoMemory;
+ if(cleanup)
+ {
+ TRAP(err, ::RunServerL());
+ delete cleanup;
+ }
+
+ __UHEAP_MARKEND;
+
+ return err;
+ }
+