persistentstorage/sql/SRC/Server/SqlSrvDatabase.cpp
changeset 0 08ec8eefde2f
child 9 667e88a979d7
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2005-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 "SqlSrvFileData.h"		//TSqlSrvFileData
       
    17 #include "SqlSrvMain.h"			//CSqlServer
       
    18 #include "SqlSrvAuthorizer.h"	//MSqlPolicyInspector
       
    19 #include "SqlSrvDatabase.h"
       
    20 #include "SqlSrvStatement.h"
       
    21 #include "SqlUtil.h"			//Panic codes, Sql2OsErrCode()
       
    22 #include "SqlSrvUtil.h"			//Global server functions
       
    23 #include "SqlCompact.h"
       
    24 #include "SqlSrvResourceProfiler.h"
       
    25 
       
    26 //
       
    27 // The following macro disables the creation/loading of the settings table.
       
    28 // It is for internal testing purposes only!
       
    29 // 
       
    30 //    __SQL_DISABLE_SYMBIAN_SETTINGS_TABLE__
       
    31 // 
       
    32 // This means that the database index will always be rebuilt when loaded by 
       
    33 // by the server regardless of the current system collation/locale in use. 
       
    34 // The benefit of enabling this macro is that a client can send PRAGMA 
       
    35 // commands to the SQL server before any tables have been explicity created in 
       
    36 // a NON-SECURE database (secure databases still automatically get a security 
       
    37 // policy table).
       
    38 //
       
    39 // The macro is applied inside:  
       
    40 //		CSqlSrvDatabase::StoreSettingsL
       
    41 // 		CSqlSrvDatabase::ProcessSettingsL
       
    42 // 
       
    43 // We should inform the user at compile-time if this macro has been enabled:
       
    44 #if defined(__SQL_DISABLE_SYMBIAN_SETTINGS_TABLE__)
       
    45 #pragma message(">>> WARNING: Use of SYMBIAN_SETTINGS table has been disabled <<<")
       
    46 #endif
       
    47 
       
    48 
       
    49 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    50 /////////////////////////////        Local const data   ///////////////////////////////////////////////////////
       
    51 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    52 
       
    53 const char* KErrMsg1 = "Missing ESCAPE expression";
       
    54 const char* KErrMsg2 = "ESCAPE expression must be a single character";
       
    55 
       
    56 ////////////////////////////////////////////////////////
       
    57 //Attach/detach SQL statements (zero-terminated strings)
       
    58 _LIT(KAttachDb, "ATTACH DATABASE :FileName AS :DbName\x0");
       
    59 _LIT(KDetachDb, "DETACH DATABASE :DbName\x0");
       
    60 ////////////////////////////////////////////////////////
       
    61 // Pragma SQL statements. The database names in all statements are quoted to avoid the "sql injection" threat.
       
    62 // (At the moment there is no way to pass an invalid database name for these statements, because the database has to be attached
       
    63 //  first and a parameter binding is used there. So, the quoting is just for safety and against changes in the future)
       
    64 _LIT(KCacheSizePragma,	"PRAGMA \"%S\".cache_size=%d\x0");
       
    65 _LIT(KPageSizePragma,	"PRAGMA \"%S\".page_size=%d\x0");
       
    66 _LIT(KAutoVacuumPragma,	"PRAGMA \"%S\".auto_vacuum=%d\x0");
       
    67 //_LIT(KPersist, "persist");
       
    68 //_LIT(KPersistentJournalPragma, "PRAGMA \"%S\".journal_mode=%S\x0");
       
    69 ////////////////////////////////////////////////////////
       
    70 //"LIKE" - user defined function name
       
    71 _LIT8(KStrLikeFuncName,  "LIKE\x0");
       
    72 
       
    73 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    74 /////////////////////////////        Local functions    ///////////////////////////////////////////////////////
       
    75 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    76 
       
    77 //Local function, used for comparing TSqlAttachDbPair objects.
       
    78 //(TSqlAttachDbPair structure represents type of the objects, members
       
    79 // of the map used for keeping the information regarding attached databases)
       
    80 //
       
    81 //Note that iKey members of aLeft and aRight function parameters are expected to be 
       
    82 //UTF8 encoded, zero-terminated strings.
       
    83 //
       
    84 //The function will panic with panic code 7 in _DEBUG mode if iKey member of aLeft or
       
    85 //aRight argument is NULL.
       
    86 static TInt Compare(const TSqlAttachDbPair& aLeft, const TSqlAttachDbPair& aRight)
       
    87 	{
       
    88 	__SQLASSERT(aLeft.iKey != NULL && aRight.iKey != NULL, ESqlPanicInternalError);
       
    89 	return ::CompareNoCase8(TPtrC8(aLeft.iKey), TPtrC8(aRight.iKey));
       
    90 	}
       
    91 
       
    92 //Local function, used for comparing TSqlCompactDbPair objects.
       
    93 //(TSqlCompactDbPair structure represents type of the objects, members
       
    94 // of the map used for keeping the information regarding compacted databases)
       
    95 //
       
    96 //Note that iKey members of aLeft and aRight function parameters are expected to be 
       
    97 //UTF16 encoded strings.
       
    98 //
       
    99 //The function will panic with panic code 7 in _DEBUG mode if iKey member of aLeft or
       
   100 //aRight argument is NULL.
       
   101 static TInt Compare2(const TSqlCompactDbPair& aLeft, const TSqlCompactDbPair& aRight)
       
   102 	{
       
   103 	__SQLASSERT(aLeft.iKey != NULL && aRight.iKey != NULL, ESqlPanicInternalError);
       
   104 	return ::CompareNoCase(*aLeft.iKey, *aRight.iKey);
       
   105 	}
       
   106 
       
   107 //Creates/opens database file (database file name in aFileData parameter) and initializes aDbHandle parameter.
       
   108 //The database will be created either with UTF-16 or UTF-8 encoding, depending on the 
       
   109 //TSqlSrvFileData::IsUTF16() property.
       
   110 static void CreateDbHandleL(const TSqlSrvFileData& aFileData, sqlite3*& aDbHandle)
       
   111 	{
       
   112 	if(aFileData.ConfigParams().iDbEncoding == TSqlSrvConfigParams::EEncUtf8)
       
   113 		{
       
   114 		TBuf8<KMaxFileName + 1> fileNameZ;
       
   115 		if(!::UTF16ZToUTF8Z(aFileData.FileNameZ(), fileNameZ))
       
   116 			{
       
   117 			__SQLLEAVE(KErrGeneral);	
       
   118 			}
       
   119 		__SQLLEAVE_IF_ERROR(::CreateDbHandle8(fileNameZ, aDbHandle));
       
   120 		}
       
   121 	else
       
   122 		{
       
   123 		__SQLLEAVE_IF_ERROR(::CreateDbHandle16(aFileData.FileNameZ(), aDbHandle));
       
   124 		}
       
   125 	}
       
   126 	
       
   127 //LoadAttachedDbSecurityPolicyLC() creates a new CSqlSecurityPolicy object and initializes it with the 
       
   128 //security policies read from the attached database file, which name is in aFileData parameter.
       
   129 //The created database security policy object is placed in the cleanup stack.
       
   130 //The caller is responsible for the destruction of the created and returned security policy object.
       
   131 //This function is used to read the security policies of attached databases.
       
   132 static CSqlSecurityPolicy* LoadAttachedDbSecurityPolicyLC(const TSqlSrvFileData& aFileData)
       
   133 	{
       
   134 	//Create new database security policy object and initialize it with a default security policy
       
   135 	TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysFail);
       
   136 	CSqlSecurityPolicy* dbPolicy = CSqlSecurityPolicy::NewLC(defaultPolicy);
       
   137 	//This is an attached  database and has to be opened
       
   138 	sqlite3* dbHandle = NULL;
       
   139 	CreateDbHandleL(aFileData, dbHandle);
       
   140 	CleanupStack::PushL(TCleanupItem(&CloseDbCleanup, dbHandle));
       
   141 	//Read the security policies.
       
   142 	TSqlDbSysSettings dbSysSettings(dbHandle);
       
   143 	dbSysSettings.LoadSecurityPolicyL(*dbPolicy);
       
   144 	CleanupStack::PopAndDestroy();//TCleanupItem(&CloseDbCleanup, dbHandle)
       
   145 	return dbPolicy;
       
   146 	}
       
   147 
       
   148 //LoadDbSecurityPolicyLC() creates a new CSqlSecurityPolicy object and initializes it with the 
       
   149 //security policies read from the database file.
       
   150 //The created database security policy object is placed in the cleanup stack.
       
   151 //The caller is responsible for destroying the returned database security policy object.
       
   152 //The function is used to read the security policy of the main database.
       
   153 static CSqlSecurityPolicy* LoadDbSecurityPolicyLC(sqlite3* aDbHandle)
       
   154 	{
       
   155 	__SQLASSERT(aDbHandle != NULL, ESqlPanicBadArgument);
       
   156 	//Create new database security policy object and initialize it with a default security policy
       
   157 	TSecurityPolicy defaultPolicy(TSecurityPolicy::EAlwaysFail);
       
   158 	CSqlSecurityPolicy* dbPolicy = CSqlSecurityPolicy::NewLC(defaultPolicy);
       
   159 	//Read the security policies.
       
   160 	TSqlDbSysSettings dbSysSettings(aDbHandle);
       
   161 	dbSysSettings.LoadSecurityPolicyL(*dbPolicy);
       
   162 	return dbPolicy;
       
   163 	}
       
   164 
       
   165 //CreateStrCopyLC() makes a copy of aSrc string and places it in the cleanup stack.
       
   166 //aSrc is expected to be UTF8 encoded, zero terminated string.
       
   167 //The function panics in _DEBUG mode if aSrc is NULL.
       
   168 static TUint8* CreateStrCopyLC(const TUint8* aSrc)
       
   169 	{
       
   170 	__SQLASSERT(aSrc != NULL, ESqlPanicBadArgument);
       
   171 	TInt len = User::StringLength(aSrc) + 1;
       
   172 	TUint8* copy = new (ELeave) TUint8[len];
       
   173 	Mem::Copy(copy, aSrc, len);
       
   174 	CleanupStack::PushL(copy);
       
   175 	return copy;
       
   176 	}
       
   177 
       
   178 //EnableAuthorizer() function is used to reenable the authorizer callback
       
   179 //during the stack cleanup.
       
   180 static void EnableAuthorizer(void* aAuthorizerDisabled)
       
   181 	{
       
   182 	__SQLASSERT(aAuthorizerDisabled != NULL, ESqlPanicBadArgument);
       
   183 	TBool* authorizerDisabled = static_cast <TBool*> (aAuthorizerDisabled);
       
   184 	*authorizerDisabled = EFalse;
       
   185 	}
       
   186 
       
   187 //Used by DbFileCleanup()
       
   188 NONSHARABLE_STRUCT(TDbFileCleanup)
       
   189 	{
       
   190 	TDbFileCleanup(const TSqlSrvFileData& aSqlSrvFileData, sqlite3*& aDbHandle) :
       
   191 		iSqlSrvFileData(aSqlSrvFileData),
       
   192 		iDbHandle(aDbHandle)
       
   193 		{
       
   194 		//aDbHandle can be NULL (it is a reference to a pointer and the pointer can be initialized later)
       
   195 		}
       
   196 	void Cleanup()
       
   197 		{
       
   198 		::CloseDbHandle(iDbHandle);//This operation also deletes the journal file
       
   199 		iDbHandle = NULL;
       
   200 		(void)iSqlSrvFileData.Fs().Delete(iSqlSrvFileData.FileName());
       
   201 		}
       
   202 private:
       
   203 	const TSqlSrvFileData&	iSqlSrvFileData;
       
   204 	sqlite3*& 				iDbHandle;
       
   205 	};
       
   206 
       
   207 //DbFileCleanup() is used to close and delete the database file during the stack cleanup, if
       
   208 //CSqlSrvDatabase's ConstructL() method(s) leave (when creating a new database file).
       
   209 static void DbFileCleanup(void* aDbFileCleanup)
       
   210 	{
       
   211 	__SQLASSERT(aDbFileCleanup != NULL, ESqlPanicBadArgument);
       
   212 	TDbFileCleanup* dbFileCleanup = static_cast <TDbFileCleanup*> (aDbFileCleanup);
       
   213 	dbFileCleanup->Cleanup();
       
   214 	}
       
   215 
       
   216 //Executes "PRAGMA" SQL statement + INTEGER value.
       
   217 //Pragma parameters:
       
   218 // aValue - integer pragma value to be set;
       
   219 // aPragma - pragma statement, the format is: ""PRAGMA <database name>.<parameter name>=%d\x0""
       
   220 // aDbName - "main" or the attached database name
       
   221 //This function is used for setting "cache_size", "page_size", "auto_vacuum" pragmas.
       
   222 //During the call the authorizer will be disabled.
       
   223 static TInt ExecPragma(sqlite3* aDbHandle, TBool& aAuthorizerDisabled, const TDesC& aPragma, TInt aValue, const TDesC& aDbName = KMainDb16)
       
   224 	{
       
   225 	__SQLASSERT(aDbHandle != NULL, ESqlPanicBadArgument);
       
   226 	TBuf<KMaxFileName + 64> pragmaSql;//(KMaxFileName + 64) characters buffer length is enough for the longest possible PRAGMA statement
       
   227 	pragmaSql.Format(aPragma, &aDbName, aValue);
       
   228 	TBool authorizerDisabledState = aAuthorizerDisabled;
       
   229 	aAuthorizerDisabled	= ETrue;
       
   230 	TInt err = DbExecStmt16(aDbHandle, pragmaSql);
       
   231 	aAuthorizerDisabled = authorizerDisabledState;
       
   232 	return err;
       
   233 	}
       
   234 
       
   235 //////////////////////////////////////////////////////////////////////////////////////////////////////
       
   236 /////////////////////////////   CSqlSrvDatabase class    /////////////////////////////////////////////
       
   237 //////////////////////////////////////////////////////////////////////////////////////////////////////
       
   238 
       
   239 
       
   240 
       
   241 /////////////////////////////   Object creation methods  /////////////////////////////////////////////
       
   242 
       
   243 /**
       
   244 Creates new CSqlSrvDatabase instance which creates and manages new secure SQL database.
       
   245 
       
   246 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
   247      			 file session reference and some other database file related properties.
       
   248 				 The format of the name must be:
       
   249 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
   250 				 "[SID]" refers to SID of the application which creates the database.
       
   251 @param aSecurityPolicy The database security policies container. 
       
   252 					   CSqlSrvDatabase instance stores the pointer in the security policy map,
       
   253 					   if it does not exist there already. The security policies map is owned by the CSqlServer class.
       
   254 
       
   255 @return A pointer to the created CSqlSrvDatabase instance.
       
   256 
       
   257 @see CSqlServer
       
   258 @see TSqlSrvFileData
       
   259 @see MSqlPolicyInspector
       
   260 @see RSqlSecurityMap
       
   261 @see CSqlSecurityPolicy
       
   262 
       
   263 @leave KErrNoMemory, an out of memory condition has occurred;
       
   264 	   KErrArgument, if a system table name found in the security policies (aSecurityPolicy);
       
   265 	   KErrAlreadyExists, the file already exists;
       
   266        KErrNotReady, the drive does not exist or is not ready;
       
   267        KErrInUse, the file is already open;
       
   268        KErrPermissionDenied, the client application does not satisfy the relevant database security policies.
       
   269                       Note that the function may also leave with some other database specific 
       
   270                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   271                       
       
   272 @panic SqlDb 4 In _DEBUG mode if aFileData does not refer to a secure database file name.
       
   273 @panic SqlDb 4 In _DEBUG mode if aSecurityPolicy is NULL.
       
   274 */
       
   275 CSqlSrvDatabase* CSqlSrvDatabase::CreateSecureL(const TSqlSrvFileData& aFileData, CSqlSecurityPolicy* aSecurityPolicy)
       
   276 	{
       
   277 	__SQLASSERT(aFileData.IsSecureFileNameFmt(), ESqlPanicBadArgument);
       
   278 	__SQLASSERT(aSecurityPolicy != NULL, ESqlPanicBadArgument);
       
   279 	if(!::SqlServer().SecurityInspector().Check(aSecurityPolicy->DbPolicy(RSqlSecurityPolicy::ESchemaPolicy)))
       
   280 		{
       
   281 		//The caller has no "SCHEMA" policy. Then the client is not given a permission to create the database.
       
   282 		//Delete aSecurityPolicy since no database object is going to be created and the security policy object 
       
   283 		//won't be put in the security policies map.
       
   284 		delete aSecurityPolicy;
       
   285 		__SQLLEAVE(KErrPermissionDenied);
       
   286 		}
       
   287 	//What does happen with aSecurityPolicy instance?
       
   288 	// If the database is created successfully, then a lookup will be made in the security policies map.
       
   289 	// (the security policies map contains reference counted security policies)
       
   290 	//    If the same security policy already exists in the map, then aSecurityPolicy will be deleted.
       
   291 	//                                          The reference counter of the found policy will be incremented.
       
   292 	//    If aSecurityPolicy is not in the map, then it will be put in the map and removed
       
   293 	//                                          from the map when CSqlSrvDatabase object is destroyed.
       
   294 	//											(the "remove" operation decrements the security policy counter
       
   295 	//											and destroys the policy if it reaches 0)
       
   296 	//
       
   297 	//The security policy map pair is:
       
   298 	//{secure_db_name, reference_counted db_security_policy}
       
   299 	//The security policy is reference counted, because the same database can be shared between one or more
       
   300 	//connections (clients), in which case only a single, reference counted instance of the database security
       
   301 	//policy is kept in the map.
       
   302 	CleanupStack::PushL(aSecurityPolicy);
       
   303 	CSqlSrvDatabase* self = new (ELeave) CSqlSrvDatabase();
       
   304 	CleanupStack::Pop(aSecurityPolicy);
       
   305 	CleanupStack::PushL(self);
       
   306 	self->ConstructCreateSecureL(aFileData, aSecurityPolicy);
       
   307 	CleanupStack::Pop(self);
       
   308 	return self;
       
   309 	}
       
   310 
       
   311 /**
       
   312 Creates new CSqlSrvDatabase instance which creates and manages new SQL database.
       
   313 
       
   314 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
   315      			 file session reference and some other database file related properties.
       
   316 
       
   317 @return A pointer to the created CSqlSrvDatabase instance.
       
   318 
       
   319 @see CSqlServer
       
   320 @see TSqlSrvFileData
       
   321 @see MSqlPolicyInspector
       
   322 @see RSqlSecurityMap
       
   323 @see CSqlSecurityPolicy
       
   324 
       
   325 @leave KErrNoMemory, an out of memory condition has occurred;
       
   326 	   KErrArgument, the file name is a name of a secure database;
       
   327 	   KErrAlreadyExists, the file already exists;
       
   328        KErrNotReady, the drive does not exist or is not ready;
       
   329        KErrInUse, the file is already open;
       
   330        KErrArgument, the file name refers to a secure database, but aSecurityPolicy is NULL;
       
   331                       Note that the function may also leave with some other database specific 
       
   332                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   333 
       
   334 @panic SqlDb 4 In _DEBUG mode if aFileData refers to a secure database file name.
       
   335 */
       
   336 CSqlSrvDatabase* CSqlSrvDatabase::CreateL(const TSqlSrvFileData& aFileData)
       
   337 	{
       
   338 	__SQLASSERT(!aFileData.IsSecureFileNameFmt(), ESqlPanicBadArgument);
       
   339 	CSqlSrvDatabase* self = new (ELeave) CSqlSrvDatabase();
       
   340 	CleanupStack::PushL(self);
       
   341 	self->ConstructCreateL(aFileData);
       
   342 	CleanupStack::Pop(self);
       
   343 	return self;
       
   344 	}
       
   345 
       
   346 /**
       
   347 Creates new CSqlSrvDatabase instance which opens and manages an existing SQL database.
       
   348 
       
   349 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
   350      			 file session reference and some other database file related properties.
       
   351 				 If this is a secure database, then the format of the name must be:
       
   352 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
   353 				 If this is a non-secure database, then the file name has to be the full database file name.
       
   354 				 "[SID]" refers to SID of the application which created the database.
       
   355 				 If this is application's private database, then the format of aFileData is as it is described
       
   356 				 in TSqlSrvFileData::SetFromHandleL() comments.
       
   357 
       
   358 @return A pointer to the created CSqlSrvDatabase instance.
       
   359 
       
   360 @leave KErrNoMemory, an out of memory condition has occurred;
       
   361        KErrNotReady, the drive does not exist or is not ready;
       
   362        KErrNotFound, the database file does not exist;
       
   363        KErrInUse, the file is already open;
       
   364        KErrPermissionDenied, the client application does not satisfy the relevant database security policies.
       
   365                       Note that the function may also leave with some other database specific 
       
   366                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   367 
       
   368 @see CSqlServer
       
   369 @see TSqlSrvFileData
       
   370 @see MSqlPolicyInspector
       
   371 @see RSqlSecurityMap
       
   372 @see CSqlSecurityPolicy
       
   373 @see TSqlSrvFileData::SetFromHandleL()
       
   374 */
       
   375 CSqlSrvDatabase* CSqlSrvDatabase::OpenL(const TSqlSrvFileData& aFileData)
       
   376 	{
       
   377 	CSqlSrvDatabase* self = new (ELeave) CSqlSrvDatabase();
       
   378 	CleanupStack::PushL(self);
       
   379 	aFileData.IsSecureFileNameFmt() ? self->ConstructOpenSecureL(aFileData) : self->ConstructOpenL(aFileData);
       
   380 	CleanupStack::Pop(self);
       
   381 	return self;
       
   382 	}
       
   383 
       
   384 /**
       
   385 Cleans up the allocated for the database connection memory and other resources.
       
   386 */
       
   387 CSqlSrvDatabase::~CSqlSrvDatabase()
       
   388 	{
       
   389     SQLPROFILER_DB_CLOSE((TUint)iDbHandle);
       
   390 	TSqlCompactDbMapIterator compactDbIt(iCompactDbMap);
       
   391 	TSqlCompactDbPair compactDbPair;
       
   392 	while(compactDbIt.Next(compactDbPair))
       
   393 		{
       
   394 		::SqlServer().Compactor().ReleaseEntry(*compactDbPair.iData);
       
   395 		}
       
   396 	iCompactDbMap.Close();
       
   397 	//If iSecureDbName is not NULL, the current CSqlSrvDatabase object operates on a secure database.
       
   398 	//The database security policy has to be removed from the security policy map.
       
   399 	//(The "remove" operation actually decrements the security policy reference counter and destroys the policy
       
   400 	//when the counter reaches 0. The counter value may be greater than 1 if the database is shared between
       
   401 	//more than one connection)
       
   402 	if(iSecureDbName)
       
   403 		{
       
   404 		::SqlServer().SecurityMap().Remove(iSecureDbName);
       
   405 		//The security policy map owns iSecureDbName and iSecurityPolicy and is responsible for 
       
   406 		//iSecureDbName and iSecurityPolicy destruction.
       
   407 		}
       
   408 	iAttachDbMap.Close();
       
   409 	::CloseDbHandle(iDbHandle);
       
   410 	}
       
   411 
       
   412 /**
       
   413 Initializes CSqlSrvDatabase data memebers with their default values.
       
   414 
       
   415 
       
   416 @see MSqlPolicyInspector
       
   417 @see RSqlSecurityMap
       
   418 @see CSqlServer
       
   419 */
       
   420 CSqlSrvDatabase::CSqlSrvDatabase() :
       
   421 	iAttachDbMap(TSqlAttachDbLinearOrder(&Compare), TSqlAttachDbDestructor()),
       
   422 	iCompactDbMap(TSqlCompactDbLinearOrder(&Compare2), TSqlCompactDbDestructor())
       
   423 	{
       
   424 	}
       
   425 	
       
   426 /**
       
   427 Creates a new SQL database file and executes config pragmas.
       
   428 This function is part of CSqlSrvDatabase instance initialization.
       
   429 If the function leaves and the error is not KErrAlreadyExists, the database file will be deleted.
       
   430 
       
   431 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
   432      			 file session reference and some other database file related properties.
       
   433 				 If this is a secure database, then the format of the name must be:
       
   434 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
   435 				 If this is a non-secure database, then the file name has to be the full database file name.
       
   436 				 "[SID]" refers to SID of the application which creates the database.
       
   437 
       
   438 @see TSqlSrvFileData
       
   439 
       
   440 @leave KErrNoMemory, an out of memory condition has occurred;
       
   441        KErrAlreadyExists, the file already exists.
       
   442                       Note that the function may also leave with some other database specific 
       
   443                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   444 */
       
   445 void CSqlSrvDatabase::CreateNewDbFileL(const TSqlSrvFileData& aFileData)
       
   446 	{
       
   447 	if(::FileExists(aFileData.Fs(), aFileData.FileName()))
       
   448 		{
       
   449 		__SQLLEAVE(KErrAlreadyExists);	
       
   450 		}		
       
   451 	TDbFileCleanup dbFileCleanup(aFileData, iDbHandle);
       
   452 	CleanupStack::PushL(TCleanupItem(&DbFileCleanup, &dbFileCleanup));
       
   453 	::CreateDbHandleL(aFileData, iDbHandle);
       
   454 	SetConfigL(aFileData.ConfigParams(), ETrue);
       
   455 	CleanupStack::Pop();//DbFileCleanup
       
   456 	}
       
   457 	
       
   458 /**
       
   459 Opens an existing SQL database file and executes config pragmas.
       
   460 
       
   461 This function is part of CSqlSrvDatabase instance initialization.
       
   462 
       
   463 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
   464      			 file session reference and some other database file related properties.
       
   465 				 If this is a secure database, then the format of the name must be:
       
   466 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
   467 				 If this is a non-secure database, then the file name has to be the full database file name.
       
   468 				 "[SID]" refers to SID of the application which creates the database.
       
   469 				 If this is application's private database, then the format of aFileData is as it is described
       
   470 				 in TSqlSrvFileData::SetFromHandleL() comments.
       
   471 				
       
   472 @leave KErrNoMemory, an out of memory condition has occurred;
       
   473        KErrNotFound, SQL database file not found.
       
   474                       Note that the function may also leave with some other database specific 
       
   475                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   476 
       
   477 @see TSqlSrvFileData
       
   478 @see TSqlSrvFileData::SetFromHandleL()
       
   479 */
       
   480 void CSqlSrvDatabase::OpenExistingDbFileL(const TSqlSrvFileData& aFileData)
       
   481 	{
       
   482 	if(!aFileData.ContainHandles())
       
   483 		{//This check is valid only if the database is outside application's private data cage
       
   484 		if(!::FileExists(aFileData.Fs(), aFileData.FileName()))
       
   485 			{
       
   486 			__SQLLEAVE(KErrNotFound);	
       
   487 			}
       
   488 		}
       
   489 	::CreateDbHandleL(aFileData, iDbHandle);
       
   490 	//this is an existing database, only the cache size can be changed, the page size is persistent database property.
       
   491 	//But for private databases, opened on the client side - the page size can be set (for the "create database" operations).
       
   492 	SetConfigL(aFileData.ConfigParams(), aFileData.ContainHandles());
       
   493 	}
       
   494 	
       
   495 /**
       
   496 Installs an authorizer callback function.
       
   497 
       
   498 The callback function is invoked by the SQL parser at SQL statement compile time for each attempt 
       
   499 to access a column of a table in the database and is used to assert the calling application's rights to
       
   500 perform specific SQL operation.
       
   501 
       
   502 This function is part of CSqlSrvDatabase instance initialization.
       
   503 
       
   504 @leave The function may leave with some database specific errors categorised as ESqlDbError.
       
   505 */
       
   506 void CSqlSrvDatabase::InstallAuthorizerL()
       
   507 	{
       
   508 	//Install the authorizer just once. "Install authorizer" may be expensive and dangerous operation because 
       
   509 	//it will expire the already prepared statements.
       
   510 	if(!iAuthorizerInstalled)
       
   511 		{
       
   512 		(void)sqlite3SymbianLastOsError();//clear last OS error
       
   513 		TInt err = sqlite3_set_authorizer(iDbHandle, &CSqlSrvDatabase::AuthorizeCallback, this);
       
   514 		__SQLLEAVE_IF_ERROR(::Sql2OsErrCode(err, sqlite3SymbianLastOsError()));
       
   515 		}
       
   516 	iAuthorizerInstalled = ETrue;
       
   517 	}
       
   518 
       
   519 #ifdef SYMBIAN_USE_SQLITE_VERSION_3_6_4
       
   520 extern "C" int sqlite3RegisterInternalUtf8Like(sqlite3 *db);
       
   521 #endif
       
   522 /**
       
   523 Installs user-defined functions. At the moment there is only one: LIKE.
       
   524 
       
   525 Replacing the LIKE operator default implementation with user defined LIKE functions.
       
   526 The default implementation need a replacement because it does not work correctly with UTF16 encoded strings.
       
   527 */
       
   528 void CSqlSrvDatabase::InstallUDFsL()
       
   529 	{
       
   530 	//Registering user defined LIKE function with 2 parameters for UTF16 encoding
       
   531 	TInt err = sqlite3_create_function(iDbHandle, reinterpret_cast <const char*> (KStrLikeFuncName().Ptr()),
       
   532 									   2/*arg*/, SQLITE_UTF16, this /*user data*/, 
       
   533 									   &CSqlSrvDatabase::LikeSqlFunc, NULL/*xStep*/, NULL/*xFinal*/);
       
   534 	__SQLLEAVE_IF_ERROR(::Sql2OsErrCode(err, sqlite3SymbianLastOsError()));
       
   535 	//Registering user defined LIKE function with 3 parameters for UTF16 encoding 
       
   536 	err = sqlite3_create_function(iDbHandle, reinterpret_cast <const char*> (KStrLikeFuncName().Ptr()),
       
   537 								  3/*arg*/, SQLITE_UTF16, this/*user data*/, 
       
   538 								  &CSqlSrvDatabase::LikeSqlFunc, NULL/*xStep*/, NULL/*xFinal*/);
       
   539 	__SQLLEAVE_IF_ERROR(::Sql2OsErrCode(err, sqlite3SymbianLastOsError()));
       
   540 	
       
   541 #ifdef SYMBIAN_USE_SQLITE_VERSION_3_6_4
       
   542 	//Registering user defined LIKE function with 2 and 3 parameters for UTF8 encoding
       
   543 	//Once registered, these will be treated as built-in functions 
       
   544 	err = sqlite3RegisterInternalUtf8Like(iDbHandle);
       
   545 	__SQLLEAVE_IF_ERROR(::Sql2OsErrCode(err, sqlite3SymbianLastOsError()));
       
   546 #endif
       
   547 	}
       
   548 
       
   549 /**
       
   550 Constructs a key for searching in the security policies map.
       
   551 
       
   552 The key is UTF8 encoded, zero-terminated string.
       
   553 
       
   554 Every time when CSqlSrvDatabase instance creates, opens or attaches a secure database, it updates
       
   555 the contents of the security policies map (RSqlSecurityMap class), which is a single instance owned 
       
   556 by the CSqlServer class.
       
   557 
       
   558 @param aDbFileName Full secure database file name, from which the security policies map key 
       
   559 				   will be constructed.
       
   560 
       
   561 @return A const pointer to the constructed security map key. No memory is allocated for the key.
       
   562 
       
   563 @leave KErrGeneral the UTF16 to UTF8 conversion of aDbFileName parameter failed.
       
   564 
       
   565 @see RSqlSecurityMap
       
   566 @see CSqlServer
       
   567 */
       
   568 const TUint8* CSqlSrvDatabase::SecurityMapKeyL(const TDesC& aDbFileName)
       
   569 	{
       
   570 	//Form the map item key - the secure database name
       
   571 	TParsePtrC parse(aDbFileName);//this call may panic if aDbFileName cannot be parsed. But aDbFileName was preprocessed by TSqlSrvFileData::Set
       
   572 	TFileName secureDbName;
       
   573 	secureDbName.Copy(parse.Drive());
       
   574 	secureDbName.Append(parse.NameAndExt());
       
   575 	secureDbName.Append(TChar(0));
       
   576 	TPtr8 ptr(iFileNameBuf, sizeof(iFileNameBuf));
       
   577 	if(!::UTF16ZToUTF8Z(secureDbName, ptr))
       
   578 		{
       
   579 		__SQLLEAVE(KErrGeneral);			
       
   580 		}
       
   581 	return iFileNameBuf;
       
   582 	}
       
   583 
       
   584 /**
       
   585 Attaches a secure or non-secure database to the current database connection.
       
   586 
       
   587 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
   588      			 file session reference and some other database file related properties.
       
   589 				 If this is a secure database, then the format of the name must be:
       
   590 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
   591 				 If this is a non-secure database, then the file name has to be the full database file name.
       
   592 				 "[SID]" refers to SID of the application which creates the database.
       
   593 @param aDbName Database name. It must be unique (per database connection). This is the name which can
       
   594                be used for accessing tables in the attached database. The syntax is "database-name.table-name".
       
   595 
       
   596 @leave KErrNotFound, the database file which has to be attached does not exist.
       
   597        KErrPermissionDenied, the client application does not satisfy the relevant security policies of
       
   598        				  the attached database.
       
   599                       Note that the function may also leave with some other database specific 
       
   600                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   601 
       
   602 @see TSqlSrvFileData
       
   603 */
       
   604 void CSqlSrvDatabase::AttachDbL(const TSqlSrvFileData& aFileData, const TDesC& aDbName)
       
   605 	{
       
   606 	if(!aFileData.ContainHandles())
       
   607 		{//This check is valid only if the database is outside application's private data cage
       
   608 		if(!::FileExists(aFileData.Fs(), aFileData.FileName()))
       
   609 			{
       
   610 			__SQLLEAVE(KErrNotFound);	
       
   611 			}
       
   612 		}
       
   613 	if(!aFileData.IsSecureFileNameFmt())		
       
   614 		{//A non-secure database to be attached -  execute the "ATTACH DB" SQL statement and initialize the attached database.
       
   615 		InitAttachedDbL(aFileData, aDbName);
       
   616 		}
       
   617 	else
       
   618 		{//A secure database has to be attached. This is a complex operation and if it fails, proper cleanup
       
   619 		 //has to be performed. "state" variable keeps the state, after which the "attach db" operation failed.
       
   620 		 //There are three things needed to be done when atatching a secure database:
       
   621 		 // 1. Executing the "ATTACH DB" SQL statement and initializing the attached database
       
   622 		 // 2. Updating the security policy map
       
   623 		 // 3. Updating the {db name, logical db name} map
       
   624 		 //The additional map (3) is needed because when the authorizer callback is called by SQLITE, the callback
       
   625 		 //is given the logical database name, if that's an operation on an attached database. Since the security 
       
   626 		 //policy map uses the database name as a key, the map (3) is used to find what is the physical database 
       
   627 		 //name, which the logical database name points to.
       
   628 		 //
       
   629 		 //There is an additional step (0), which may happen when a secure database is attached to a 
       
   630 		 //non-secure database. But this step does not require a cleanup.
       
   631 		CSqlSrvDatabase::TAttachState state = CSqlSrvDatabase::EAStNone;
       
   632 		const TUint8* securityMapKey = NULL;
       
   633 		TRAPD(err, DoAttachSecureDbL(state, aFileData, aDbName, securityMapKey));
       
   634 		if(err != KErrNone)
       
   635 			{
       
   636 			//Cleanup
       
   637 			if(state > CSqlSrvDatabase::EAStNone)
       
   638 				{
       
   639 				(void)FinalizeAttachedDb(aDbName);
       
   640 				if(state > CSqlSrvDatabase::EAStDbAttached)
       
   641 					{
       
   642 					::SqlServer().SecurityMap().Remove(securityMapKey);
       
   643 					}
       
   644 				}
       
   645 			__SQLLEAVE(err);
       
   646 			}
       
   647 		}
       
   648 	}
       
   649 
       
   650 /**
       
   651 Attaches a secure database to the existing connection.
       
   652 
       
   653 The function also updates the following maps:
       
   654 - Security policies map (CSqlServer::iSecurityMap), where a reference counted copy of database security policies
       
   655   is kept for each created/opened/attached database during the life time of the SQL server;
       
   656 - Attached secure databases map (CSqlSrvDatabase::iAttachDbMap), where an information is kept what SQL database
       
   657   file name corresponds to a specific attached database name. This information is used by the authorizer callback
       
   658   function in order to find what database security policies have to be asserted when a SQL operation is issued
       
   659   for a particular attached database (the attached database name is identified always by its name, not the file name);
       
   660 
       
   661 @param aState Output parameter - the attach progress state, used by the calling function to perform correctly 
       
   662 			  the cleanup, if the attach operation fails.
       
   663 			  It may have the following values set:
       
   664 			  - CSqlSrvDatabase::EAStNone - no resources need to be freed;
       
   665 			  - CSqlSrvDatabase::EAStDbAttached - the function was able to execute the "ATTACH DATABASE"
       
   666 			      SQL statement before an error occured. The calling function has to execute "DETACH DATABASE"
       
   667 			      SQL statement to detach the database;
       
   668 			  - CSqlSrvDatabase::EAStSecurityMapUpdated - the function was able to update the security policies
       
   669 			      map (CSqlServer::iSecurityMap) before an error occured. The calling function has to remove
       
   670 			      the attached database security policies from the map and detach the database.
       
   671 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
   672      			 file session reference and some other database file related properties.
       
   673 				 The secure database name format must be:
       
   674 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
   675 				 "[SID]" refers to SID of the application which creates the database.
       
   676 @param aDbName Database name. It must be unique (per database connection). This is the name which can
       
   677                be used for accessing tables in the attached database. The syntax is "database-name.table-name".
       
   678 @param aMapKey Output parameter, UTF8 encoded, zero-terminated string, which can be used for searching 
       
   679 			   of the attached database security policies in the security policies map (CSqlServer::iSecurityMap). 
       
   680 			   No memory is allocated for the key.
       
   681 
       
   682 @see RSqlSecurityMap
       
   683 @see RSqlAttachDbMap
       
   684 @see CSqlServer
       
   685 @see TSqlSrvFileData
       
   686 @see CSqlSrvDatabase
       
   687 
       
   688 @leave KErrNoMemory, an out of memory condition has occurred;
       
   689        KErrPermissionDenied, the client application does not satisfy the relevant security policies of
       
   690        				  the attached database.
       
   691                       Note that the function may also leave with some other database specific 
       
   692                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   693 */
       
   694 void CSqlSrvDatabase::DoAttachSecureDbL(CSqlSrvDatabase::TAttachState& aState, 
       
   695 										const TSqlSrvFileData& aFileData, 
       
   696 										const TDesC& aDbName, const TUint8*& aMapKey)
       
   697 	{
       
   698 	//Step 1: Attach the database and initialize the attached database
       
   699 	InitAttachedDbL(aFileData, aDbName);
       
   700 	aState = CSqlSrvDatabase::EAStDbAttached;
       
   701 	//Step 2: Load the database security policy and update the security map
       
   702 	const CSqlSecurityPolicy* securityPolicy = NULL;
       
   703 	UpdateSecurityMapL(ETrue, aFileData, aMapKey, securityPolicy);
       
   704 	aState = CSqlSrvDatabase::EAStSecurityMapUpdated;
       
   705 	//Check that the caller has at least one of {Schema, Read, Write} policies.
       
   706 	BasicSecurityPolicyCheckL(*securityPolicy);
       
   707 	//Step 3: Update the attached databases map
       
   708 	InsertInAttachDbMapL(aFileData.FileName(), aDbName);
       
   709 	}
       
   710 	
       
   711 /**
       
   712 Detaches a database from the current database connection.
       
   713 
       
   714 The function also will search the security policies map (CSqlServer::iSecurityMap) and the attached databases
       
   715 map (CSqlSrvDatabase::iAttachDbMap) for entries which correspond to the database ,
       
   716 which is about to be detached, and will remove the entries.
       
   717 
       
   718 @param aDbName Attached database name. It must be unique (per database connection).
       
   719 
       
   720 @leave The function may leave with some database specific errors categorised as ESqlDbError, 
       
   721 	   and other system-wide error codes.
       
   722 	   
       
   723 @see CSqlSrvDatabase::DoAttachSecureDbL()
       
   724 @see RSqlSecurityMap
       
   725 @see RSqlAttachDbMap
       
   726 @see CSqlServer
       
   727 @see CSqlSrvDatabase
       
   728 */
       
   729 void CSqlSrvDatabase::DetachDbL(const TDesC& aDbName)
       
   730 	{
       
   731 	TInt err = FinalizeAttachedDb(aDbName);
       
   732 	if(err == KErrNone)
       
   733 		{
       
   734 		TRAP(err, RemoveFromMapsL(aDbName));//ignore the error
       
   735 		}
       
   736 	else
       
   737 		{
       
   738 		__SQLLEAVE(err);
       
   739 		}
       
   740 	}
       
   741 
       
   742 /**
       
   743 Calculates and returns the database size. 
       
   744 
       
   745 @param aDbName Attached database name or KNullDesC for the main database
       
   746 
       
   747 @leave The function may leave with some database specific errors categorised as ESqlDbError, 
       
   748 	   and other system-wide error codes.
       
   749 
       
   750 @return Database size in bytes.
       
   751 */
       
   752 TInt64 CSqlSrvDatabase::SizeL(const TDesC& aDbName)
       
   753 	{
       
   754 	iAuthorizerDisabled	= ETrue;
       
   755 	CleanupStack::PushL(TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled));
       
   756 	TInt pageCount = 0;
       
   757 	__SQLLEAVE_IF_ERROR(::DbPageCount(iDbHandle, aDbName, pageCount));
       
   758 	__SQLASSERT(pageCount >= 0, ESqlPanicInternalError);
       
   759 	CleanupStack::PopAndDestroy();
       
   760 	return (TInt64)pageCount * PageSizeL(aDbName);
       
   761 	}
       
   762 
       
   763 /**
       
   764 Retrieves the database free space. 
       
   765 
       
   766 @param aDbName Attached database name or KNullDesC for the main database
       
   767 
       
   768 @return Database free space in bytes.
       
   769 
       
   770 @leave The function may leave with some database specific errors categorised as ESqlDbError, 
       
   771 	   and other system-wide error codes.
       
   772 */
       
   773 TInt64 CSqlSrvDatabase::FreeSpaceL(const TDesC& aDbName)
       
   774 	{
       
   775 	iAuthorizerDisabled	= ETrue;
       
   776 	CleanupStack::PushL(TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled));
       
   777 	TInt freePageCount = 0;
       
   778 	__SQLLEAVE_IF_ERROR(::DbFreePageCount(iDbHandle, aDbName, freePageCount));
       
   779 	CleanupStack::PopAndDestroy();
       
   780 	__SQLASSERT(freePageCount >= 0, ESqlPanicInternalError);
       
   781 	return (TInt64)freePageCount * PageSizeL(aDbName);
       
   782 	}
       
   783 
       
   784 /**
       
   785 Collects information regarding the current cache size, page, size, encoding, etc. and puts the values
       
   786 in the aDest output string.
       
   787 
       
   788 @param aDest Output parameter, where the result values will be stored. The string format is: "<val1>;<val2>...;".
       
   789 
       
   790 @leave The function may leave with some database specific errors categorised as ESqlDbError, 
       
   791 	   and other system-wide error codes.
       
   792 */
       
   793 void CSqlSrvDatabase::QueryConfigL(TDes8& aDest)
       
   794 	{
       
   795 	iAuthorizerDisabled	= ETrue;
       
   796 	CleanupStack::PushL(TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled));
       
   797 
       
   798 	TInt cacheSize = 0;
       
   799 	__SQLLEAVE_IF_ERROR(::DbCacheSize(iDbHandle, KNullDesC, cacheSize));
       
   800 	
       
   801 	TInt pageSize = 0;
       
   802 	__SQLLEAVE_IF_ERROR(::DbPageSize(iDbHandle, KNullDesC, pageSize));
       
   803 
       
   804 	TBuf8<16> encoding;
       
   805 	__SQLLEAVE_IF_ERROR(::DbEncoding(iDbHandle, KNullDesC, encoding));
       
   806 
       
   807 	TInt defaultSoftHeapLimit = TSqlSrvConfigParams::KDefaultSoftHeapLimitKb;
       
   808 
       
   809 	TInt vacuum = 0;
       
   810 	__SQLLEAVE_IF_ERROR(::DbVacuumMode(iDbHandle, KNullDesC, vacuum));
       
   811 
       
   812 	aDest.AppendNum(cacheSize);	
       
   813 	_LIT8(KSemiColon, ";");
       
   814 	aDest.Append(KSemiColon);	
       
   815 	aDest.AppendNum(pageSize);	
       
   816 	aDest.Append(KSemiColon);	
       
   817 	aDest.Append(encoding);	
       
   818 	aDest.Append(KSemiColon);	
       
   819 	aDest.AppendNum(defaultSoftHeapLimit);	
       
   820 	aDest.Append(KSemiColon);	
       
   821 	aDest.AppendNum(vacuum);	
       
   822 	aDest.Append(KSemiColon);	
       
   823 	
       
   824 	CleanupStack::PopAndDestroy();
       
   825 	}
       
   826 
       
   827 /**
       
   828 Compacts the database free space. 
       
   829 
       
   830 @param aSize The requested database space to be compacted, in bytes.
       
   831 			 If aSize value is RSqlDatabase::EMaxCompaction, then all free pages will be removed.
       
   832 			 Note that the requested space to be compacted will be rounded up to the nearest page count,
       
   833 			 e.g. request for removing 1 byte will remove one free page from the database file. 
       
   834 
       
   835 @param aDbName Attached database name or KNullDesC for the main database
       
   836 
       
   837 @return The size of the removed free space
       
   838 
       
   839 @leave The function may leave with some database specific errors categorised as ESqlDbError, 
       
   840 	   and other system-wide error codes.
       
   841 */
       
   842 TInt CSqlSrvDatabase::CompactL(TInt aSize, const TDesC& aDbName)
       
   843 	{
       
   844 	__SQLASSERT(aSize > 0 || aSize == RSqlDatabase::EMaxCompaction, ESqlPanicBadArgument);
       
   845 	TInt pageSize = PageSizeL(aDbName);//PageSizeL() will disable/enable the authorizer
       
   846 	TInt pageCount = KMaxTInt;
       
   847 	if(aSize > 0)
       
   848 		{//64-bit calculations to avoid the overflow in case if (aSize + pageSize) >= KMaxTInt.
       
   849 		pageCount = (TInt64)((TInt64)aSize + pageSize - 1) / pageSize;
       
   850 		}
       
   851 	if(pageCount > 0)
       
   852 		{
       
   853 		iAuthorizerDisabled	= ETrue;
       
   854 		CleanupStack::PushL(TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled));
       
   855 		__SQLLEAVE_IF_ERROR(::DbCompact(iDbHandle, aDbName, pageCount, pageCount));
       
   856 		CleanupStack::PopAndDestroy();
       
   857 		}
       
   858 	return pageCount * pageSize;
       
   859 	}
       
   860 
       
   861 /**
       
   862 This structure is used in case if the InitAttachedDbL() execution fails and the 
       
   863 executed operations ("attach database", "init compact") have to be reverted calling
       
   864 FinalizeAttachedDb().
       
   865 
       
   866 @see CSqlSrvDatabase::InitAttachedDbL
       
   867 @see CSqlSrvDatabase::FinalizeAttachedDb
       
   868 @see CSqlSrvDatabase::AttachCleanup
       
   869 
       
   870 @internalComponent
       
   871 */
       
   872 NONSHARABLE_STRUCT(TAttachCleanup)
       
   873 	{
       
   874 	inline TAttachCleanup(CSqlSrvDatabase& aSelf, const TDesC& aDbName) :
       
   875 		iSelf(aSelf),
       
   876 		iDbName(aDbName)
       
   877 		{
       
   878 		}
       
   879 	CSqlSrvDatabase& iSelf;
       
   880 	const TDesC& iDbName;
       
   881 	};
       
   882 
       
   883 /**
       
   884 Cleanup function. Calls FinalizeAttachedDb() if InitAttachedDbL() has failed.
       
   885 
       
   886 @param aCleanup A pointer to a TAttachCleanup object that contains the needed for the cleanup information.
       
   887 
       
   888 @see TAttachCleanup
       
   889 
       
   890 @internalComponent
       
   891 */
       
   892 void CSqlSrvDatabase::AttachCleanup(void* aCleanup)
       
   893 	{
       
   894 	TAttachCleanup* cleanup = reinterpret_cast <TAttachCleanup*> (aCleanup);
       
   895 	__SQLASSERT(cleanup != NULL, ESqlPanicBadArgument);
       
   896 	if(cleanup)
       
   897 		{
       
   898 		(void)cleanup->iSelf.FinalizeAttachedDb(cleanup->iDbName);
       
   899 		}
       
   900 	}
       
   901 
       
   902 /**
       
   903 Forms and executes "ATTACH DATABASE" SQL statement.
       
   904 If the database is not read-only:
       
   905  - Makes the attached database journal file persistent.
       
   906  - Initializes the attached database compaction mode.
       
   907  - The attached database will be reindexed if the default collation has been changed.
       
   908 
       
   909 @param aFileData Attached database file data
       
   910 @param aDbName Attached database name. It must be unique (per database connection).
       
   911 
       
   912 @leave KErrNoMemory, an out of memory condition has occurred;
       
   913                       Note that the function may also leave with some other database specific 
       
   914                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   915                       
       
   916 @see InitCompactionL
       
   917 @see ProcessSettingsL
       
   918 */
       
   919 void CSqlSrvDatabase::InitAttachedDbL(const TSqlSrvFileData& aFileData, const TDesC& aDbName)
       
   920 	{
       
   921 	TPtrC dbFileName = aFileData.FileName();
       
   922 	TBool readOnlyDbFile = aFileData.IsReadOnly();
       
   923 	
       
   924 	InstallAuthorizerL();
       
   925 	iAuthorizerDisabled	= ETrue;
       
   926 	CleanupStack::PushL(TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled));
       
   927 	sqlite3_stmt* stmtHandle = StmtPrepare16L(iDbHandle, KAttachDb);
       
   928 	TInt err = ::Sql2OsErrCode(sqlite3_bind_text16(stmtHandle, 1, dbFileName.Ptr(), dbFileName.Length() * sizeof(TUint16), SQLITE_STATIC), sqlite3SymbianLastOsError());
       
   929 	if(err == KErrNone)
       
   930 		{
       
   931 		err = ::Sql2OsErrCode(sqlite3_bind_text16(stmtHandle, 2, aDbName.Ptr(), aDbName.Length() * sizeof(TUint16), SQLITE_STATIC), sqlite3SymbianLastOsError());
       
   932 		if(err == KErrNone)
       
   933 			{
       
   934 			err = StmtExec(stmtHandle);
       
   935 			}
       
   936 		}
       
   937 	TInt err2 = ::FinalizeStmtHandle(stmtHandle);
       
   938 	CleanupStack::PopAndDestroy();//TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled)
       
   939 	if(err == KErrNone && err2 != KErrNone)
       
   940 		{//::FinalizeStmtHandle() has failed
       
   941 		err = err2;
       
   942 		}
       
   943 	__SQLLEAVE_IF_ERROR(err);
       
   944 	
       
   945 	TAttachCleanup attachCleanup(*this, aDbName);
       
   946 	CleanupStack::PushL(TCleanupItem(&CSqlSrvDatabase::AttachCleanup, &attachCleanup));
       
   947 	
       
   948 	SetConfigL(aFileData.ConfigParams(), EFalse, aDbName);
       
   949 	
       
   950 	if(!readOnlyDbFile)
       
   951 		{
       
   952 		iAuthorizerDisabled	= ETrue;
       
   953 		CleanupStack::PushL(TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled));
       
   954 		ProcessSettingsL(aFileData, aDbName);
       
   955 		CleanupStack::PopAndDestroy();//TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled)
       
   956 		}
       
   957 	
       
   958 	CleanupStack::Pop();//TCleanupItem(&CSqlSrvDatabase::AttachCleanup, &attachCleanup)
       
   959 	}
       
   960 
       
   961 /**
       
   962 Forms and executes "DETACH DATABASE" SQL statement.
       
   963 If the database was scheduled for background compacting, the related database entry will be removed from
       
   964 the vaccum db map.
       
   965 
       
   966 @param aDbName Attached database name. It must be unique (per database connection).
       
   967 
       
   968 @return KErrNone, Operation completed successfully;
       
   969 		KErrNoMemory, an out of memory condition has occurred.
       
   970                       Note that the function may also return some other database specific 
       
   971                       errors categorised as ESqlDbError, and other system-wide error codes.
       
   972 */
       
   973 TInt CSqlSrvDatabase::FinalizeAttachedDb(const TDesC& aDbName)
       
   974 	{
       
   975 	ReleaseCompactEntry(aDbName);
       
   976 	iAuthorizerDisabled	= ETrue;
       
   977 	sqlite3_stmt* stmtHandle = NULL;
       
   978 	TRAPD(err, stmtHandle = StmtPrepare16L(iDbHandle, KDetachDb));
       
   979 	if(err == KErrNone)
       
   980 		{
       
   981 		err = ::Sql2OsErrCode(sqlite3_bind_text16(stmtHandle, 1, aDbName.Ptr(), aDbName.Length() * sizeof(TUint16), SQLITE_STATIC), sqlite3SymbianLastOsError());
       
   982 		if(err == KErrNone)
       
   983 			{
       
   984 			err = StmtExec(stmtHandle);
       
   985 			}
       
   986 		}
       
   987 	TInt err2 = ::FinalizeStmtHandle(stmtHandle);
       
   988 	if(err == KErrNone && err2 != KErrNone)
       
   989 		{//::FinalizeStmtHandle() has failed
       
   990 		err = err2;
       
   991 		}
       
   992 	iAuthorizerDisabled	= EFalse;
       
   993 	return err;
       
   994 	}
       
   995 
       
   996 /**
       
   997 Updates the security policies map (CSqlServer::iSecurityMap).
       
   998 
       
   999 Inserts a new item in the security map, or if such item already exists there - its reference counter will
       
  1000 be incremented.
       
  1001 The method guarantees that either the security map will be updated, or the method leaves and the security
       
  1002 policies map stays unchanged.
       
  1003 
       
  1004 @param aAttachedDb True if the currently processed database is an attached database, false if it is the main db.
       
  1005 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
  1006      			 file session reference and some other database file related properties.
       
  1007 				 The secure database name format must be:
       
  1008 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
  1009 				 "[SID]" refers to SID of the application which creates the database.
       
  1010 @param aMapKey Output parameter. UTF8 encoded, zero-terminated string. On function exit cannot be NULL. 
       
  1011                It will be set to point to the security policies map key. No memory is allocated for the key.
       
  1012 @param aSecurityPolicy Output parameter. On function exit cannot be NULL. It will be set to point to the security policies.
       
  1013 
       
  1014 @leave KErrNoMemory, an out of memory condition has occurred;
       
  1015                       Note that the function may also leave with some other database specific 
       
  1016                       errors categorised as ESqlDbError, and other system-wide error codes.
       
  1017 
       
  1018 @see RSqlSecurityMap
       
  1019 @see CSqlServer
       
  1020 @see TSqlSrvFileData
       
  1021 @see CSqlSecurityPolicy
       
  1022 */
       
  1023 void CSqlSrvDatabase::UpdateSecurityMapL(TBool aAttachedDb, const TSqlSrvFileData& aFileData, 
       
  1024 										 const TUint8*& aMapKey, const CSqlSecurityPolicy*& aSecurityPolicy)
       
  1025 	{
       
  1026 	//Check if a copy of the database security policies is already in the security map.
       
  1027 	aMapKey = SecurityMapKeyL(aFileData.FileName());
       
  1028 	TSqlSecurityPair* pair = ::SqlServer().SecurityMap().Entry(aMapKey);
       
  1029 	if(pair)
       
  1030 		{
       
  1031 		//Yes, it is in the map. Increment the reference counter.
       
  1032 		//(It will be decremented when detaching the database).
       
  1033 		pair->iRefCounter.Increment();
       
  1034 		aMapKey = pair->iKey;
       
  1035 		aSecurityPolicy = pair->iData;
       
  1036 		}
       
  1037 	else
       
  1038 		{
       
  1039 		//No, it is not in the map. Read the security policies from the security policies tables and 
       
  1040 		//insert a new item in the map.
       
  1041 		__SQLASSERT(aMapKey != NULL, ESqlPanicInternalError);
       
  1042 		aMapKey = ::CreateStrCopyLC(aMapKey);
       
  1043 		CSqlSecurityPolicy* securityPolicy = aAttachedDb ? ::LoadAttachedDbSecurityPolicyLC(aFileData) :
       
  1044 		                                                   ::LoadDbSecurityPolicyLC(iDbHandle);
       
  1045 		__SQLLEAVE_IF_ERROR(::SqlServer().SecurityMap().Insert(aMapKey, securityPolicy));
       
  1046 		CleanupStack::Pop(2);//iSecurityMap owns aMapKey and securityPolicy objects
       
  1047 		aSecurityPolicy = securityPolicy;
       
  1048 		}
       
  1049 	__SQLASSERT(aMapKey != NULL, ESqlPanicInternalError);
       
  1050 	__SQLASSERT(aSecurityPolicy != NULL, ESqlPanicInternalError);
       
  1051 	}
       
  1052 
       
  1053 /**
       
  1054 Removes attached secure database entries from the maps.
       
  1055 
       
  1056 The function will search the security policies map (CSqlServer::iSecurityMap) and the attached databases
       
  1057 map (CSqlSrvDatabase::iAttachDbMap) for entries which correspond to the database with aDbName name,
       
  1058 and will remove the entries.
       
  1059 
       
  1060 The sequence of the performed by the function operations is:
       
  1061 1. Looks for a map item which key is aDbName in iAttachDbMap map.
       
  1062 2. If such pair exists, the data part of the pair is used as a key in iSecurityMap map.
       
  1063 3. Remove the iSecurityMap map item pointed by the data part of the found pair.
       
  1064 4. Remove the iAttachDbMap map item pointed by aDbName.
       
  1065 
       
  1066 @param aDbName Attached database name. It must be unique (per database connection).
       
  1067 
       
  1068 @leave KErrGeneral It is not possible to convert aDbName parameter to UTF8 encoded string.
       
  1069 
       
  1070 @see CSqlSrvDatabase::DoAttachDbL()
       
  1071 @see CSqlSrvDatabase::DoAttachSecureDbL()
       
  1072 @see RSqlSecurityMap
       
  1073 @see RSqlAttachDbMap
       
  1074 @see CSqlServer
       
  1075 @see CSqlSrvDatabase
       
  1076 */
       
  1077 void CSqlSrvDatabase::RemoveFromMapsL(const TDesC& aDbName)
       
  1078 	{
       
  1079 	TPtr8 ptr(iFileNameBuf, sizeof(iFileNameBuf));
       
  1080 	if(!::UTF16ToUTF8Z(aDbName, ptr))
       
  1081 		{
       
  1082 		__SQLLEAVE(KErrGeneral);	
       
  1083 		}
       
  1084 	TSqlAttachDbPair* attachDbPair = iAttachDbMap.Entry(iFileNameBuf);
       
  1085 	if(attachDbPair)
       
  1086 		{//aDbName refers to attached secure database
       
  1087 		::SqlServer().SecurityMap().Remove(attachDbPair->iData);
       
  1088 		iAttachDbMap.Remove(iFileNameBuf);
       
  1089 		}
       
  1090 	}
       
  1091 
       
  1092 /**
       
  1093 Inserts a new entry in the attached databases map (CSqlSrvDatabase::iAttachDbMap).
       
  1094 
       
  1095 The method guarantees that either a new [logical db name, secure db name] pair will be inserted in
       
  1096 iAttachDbMap or the method fails and the content of iAttachDbMap remains unchanged.
       
  1097 
       
  1098 @param aDbFileName Database file name, including the path.
       
  1099 @param aDbName Database name.
       
  1100 
       
  1101 @leave KErrNoMemory, an out of memory condition has occurred;
       
  1102 	   KErrGeneral, it is not possible to convert the function parameters to UTF8 encoded strings.
       
  1103 
       
  1104 @see RSqlAttachDbMap
       
  1105 @see CSqlSrvDatabase
       
  1106 */
       
  1107 void CSqlSrvDatabase::InsertInAttachDbMapL(const TDesC& aDbFileName, const TDesC& aDbName)
       
  1108 	{
       
  1109 	//Convert aDbName to UTF8, zero-terminated name
       
  1110 	TPtr8 ptr(iFileNameBuf, sizeof(iFileNameBuf));
       
  1111 	if(!::UTF16ToUTF8Z(aDbName, ptr))
       
  1112 		{
       
  1113 		__SQLLEAVE(KErrGeneral);	
       
  1114 		}
       
  1115 	const TUint8* mapKey = ::CreateStrCopyLC(iFileNameBuf);
       
  1116 	const TUint8* mapData = SecurityMapKeyL(aDbFileName);
       
  1117 	mapData = ::CreateStrCopyLC(mapData);
       
  1118 	__SQLLEAVE_IF_ERROR(iAttachDbMap.Insert(mapKey, mapData));
       
  1119 	CleanupStack::Pop(2);//iAttachDbMap owns mapKey amd mapData.
       
  1120 	}
       
  1121 
       
  1122 /**
       
  1123 Processes the database settings that are currently stored in the settings table.
       
  1124 Makes the journal file persistent.
       
  1125 Initializes the database compaction mode.
       
  1126 Based on the current settings the database may be configured to become 'up-to-date'.
       
  1127 This configuration may include reindexing the database if the collation dll has
       
  1128 changed and/or executing database configuration file operations.
       
  1129 
       
  1130 @param aFileData The file data object,
       
  1131 @param aDbName Logical database name: "main" for the main database or attached database name,
       
  1132 				        
       
  1133 @leave The function may leave with system-wide error codes or SQL errors of ESqlDbError type
       
  1134 
       
  1135 @panic SqlDb 7 In _DEBUG mode if aFileData does not refer to a r/w database file.
       
  1136 */
       
  1137 void CSqlSrvDatabase::ProcessSettingsL(const TSqlSrvFileData& aFileData, const TDesC& aDbName)
       
  1138 	{
       
  1139 	__SQLASSERT(!aFileData.IsReadOnly(), ESqlPanicInternalError);
       
  1140 #if !defined(__SQL_DISABLE_SYMBIAN_SETTINGS_TABLE__)
       
  1141 	//Make the journal file persistent - done by SQLite automatically because the locking mode is EXCLUSIVE
       
  1142 	//__SQLLEAVE_IF_ERROR(::ExecPragma(iDbHandle, iAuthorizerDisabled, KPersistentJournalPragma, KPersist, aDbName));
       
  1143 	//Load the current settings
       
  1144 	TFileName storedCollationDllName;
       
  1145 	TInt storedDbConfigFileVer = -1;
       
  1146 	TInt currVacuumMode = -1;
       
  1147 	__SQLLEAVE_IF_ERROR(::DbVacuumMode(iDbHandle, aDbName, currVacuumMode));
       
  1148 	//currVacuumMode == ESqliteVacuumOff ==> This is a database created not by the SQL server
       
  1149 	TSqlCompactionMode compactionMode = currVacuumMode == ESqliteVacuumOff ? ESqlCompactionManual : ESqlCompactionNotSet;
       
  1150 	TSqlDbSysSettings dbSettings(iDbHandle);
       
  1151 	dbSettings.LoadSettingsL(aDbName, storedCollationDllName, storedDbConfigFileVer, compactionMode);
       
  1152 	__SQLASSERT(currVacuumMode == ESqliteVacuumOff ? compactionMode == ESqlCompactionManual : 1, ESqlPanicInternalError);
       
  1153 	if(aFileData.ContainHandles() && aFileData.IsCreated())
       
  1154 		{
       
  1155 		compactionMode = aFileData.ConfigParams().iCompactionMode;
       
  1156 		if(compactionMode == ESqlCompactionNotSet)
       
  1157 			{
       
  1158 			compactionMode = KSqlDefaultCompactionMode;
       
  1159 			}
       
  1160 		//This is a just created private database. Store the compaction mode (the compaction mode may have been set using a config string).
       
  1161 		StoreSettingsL(storedCollationDllName, storedDbConfigFileVer, compactionMode);
       
  1162 		}
       
  1163 	//Init the database compaction mode
       
  1164 	InitCompactionL(compactionMode, aFileData.ConfigParams().iFreePageThresholdKb, aFileData.FileName(), 
       
  1165 					(TSqliteVacuumMode)currVacuumMode, aDbName);
       
  1166 	//Based on the current settings, apply any necessary configuration updates to the database
       
  1167 	ApplyConfigUpdatesL(storedCollationDllName, storedDbConfigFileVer, aFileData, aDbName);	
       
  1168 #endif // !(__SQL_DISABLE_SYMBIAN_SETTINGS_TABLE__)			
       
  1169 	}
       
  1170 		
       
  1171 /**
       
  1172 Applies any necessary configuration updates to the database, based on the current settings 
       
  1173 in the settings table and how the database is being used (i.e. 'Opened' or 'Attached'). 
       
  1174 The applied configuration may include:
       
  1175 - Reindexing the main database and all attached databases, if the collation dll has been changed.
       
  1176 After the reindexation the new collation dll name will be stored in the settings table of the database.
       
  1177 - Executing all supported operations on the database that are specified in a database configuration 
       
  1178 file, if such a file exists and has not already been processed. 
       
  1179 The settings table will updated with the current version of the database configuration file if the file 
       
  1180 is processed.
       
  1181 
       
  1182 @param aStoredCollationDllName The name of the collation dll that is stored in the settings table,
       
  1183 @param aStoredDbConfigFileVersion The database configuration file version that is stored in the settings table,
       
  1184 @param aFileData   The file data object,
       
  1185 @param aDbName Logical database name: "main" for the main database or attached database name,
       
  1186 
       
  1187 @leave The function may leave with system-wide error codes or SQL errors of ESqlDbError type
       
  1188 */
       
  1189 void CSqlSrvDatabase::ApplyConfigUpdatesL(const TDesC& aStoredCollationDllName, const TInt& aStoredDbConfigFileVersion, 
       
  1190 										  const TSqlSrvFileData& aFileData, const TDesC& aDbName)
       
  1191 	{
       
  1192 	TSqlDbSysSettings dbSettings(iDbHandle);
       
  1193 	//Check whether reindexing is necessary
       
  1194 	if(::SqlServer().CollationDllName().CompareF(aStoredCollationDllName) != 0)
       
  1195 		{
       
  1196 		dbSettings.ReindexDatabaseL(aDbName, ::SqlServer().CollationDllName());
       
  1197 		}
       
  1198 
       
  1199 	//Perform any necessary configuration file updates to the database.
       
  1200 	//We do not want failures here to cause the database to fail
       
  1201 	//to be opened and so any leave error is TRAPed and ignored
       
  1202 	//(the error is logged in _DEBUG mode)
       
  1203 	TRAPD(err, dbSettings.ConfigureDatabaseL(aStoredDbConfigFileVersion, aFileData, aDbName));
       
  1204 	if(KErrNone != err)
       
  1205 		{
       
  1206 		__SQLLOG_ERR(_L("SQLLOG: CSqlSrvDatabase::ApplyConfigUpdatesL() - ConfigureDatabaseL() failed with error code %d"), err);	
       
  1207 		}
       
  1208 	}
       
  1209 
       
  1210 /**
       
  1211 Sets the "cache size" and "page size" parameter values, if their values are valid.
       
  1212 This is done formatting and executing PRAGMA statements.
       
  1213 @param aConfigParams   This object contains the cofiguration parameters
       
  1214 @param aSetPageSize If true, the page size will be set, otherwise not.
       
  1215                     The aSetPageSize is set to true if:
       
  1216                     1) The operation is "create database"
       
  1217                     2) The operation is "open private database"
       
  1218 @param aLogicalDbName Parameter with default value of KNullDesC. If aLogicalDbName length is not 0, then the 
       
  1219                       "cache_size" pragma will be executed on the attached database with aLogicalDbName name. 
       
  1220 */
       
  1221 void CSqlSrvDatabase::SetConfigL(const TSqlSrvConfigParams& aConfigParams, TBool aSetPageSize, const TDesC& aLogicalDbName)
       
  1222 	{
       
  1223 	__SQLASSERT(aConfigParams.iPageSize == TSqlSrvConfigParams::KConfigPrmValueNotSet || aConfigParams.iPageSize >= 0, ESqlPanicBadArgument);
       
  1224 	__SQLASSERT(aConfigParams.iCacheSize == TSqlSrvConfigParams::KConfigPrmValueNotSet || aConfigParams.iCacheSize >= 0, ESqlPanicBadArgument);
       
  1225 	if(aSetPageSize && aConfigParams.iPageSize != TSqlSrvConfigParams::KConfigPrmValueNotSet)
       
  1226 		{
       
  1227 		__SQLLEAVE_IF_ERROR(::ExecPragma(iDbHandle, iAuthorizerDisabled, KPageSizePragma, aConfigParams.iPageSize));
       
  1228 		}
       
  1229 	
       
  1230 	const TDesC& logicalDbName = aLogicalDbName.Length() > 0 ? aLogicalDbName : KMainDb16;
       
  1231 	
       
  1232 	//Setting the cache size.
       
  1233 	//Step 1: Check if aConfigParams.iCacheSize value is set. If it is set, then use it.
       
  1234 	if(aConfigParams.iCacheSize != TSqlSrvConfigParams::KConfigPrmValueNotSet)
       
  1235 		{
       
  1236 		__SQLLEAVE_IF_ERROR(::ExecPragma(iDbHandle, iAuthorizerDisabled, KCacheSizePragma, aConfigParams.iCacheSize, logicalDbName));
       
  1237 		}
       
  1238 	else
       
  1239 		{
       
  1240 	//Step 2: aConfigParams.iCacheSize value is not set. Then check if aConfigParams.iSoftHeapLimitKb value is set.
       
  1241 		if(aConfigParams.iSoftHeapLimitKb != TSqlSrvConfigParams::KConfigPrmValueNotSet)
       
  1242 			{
       
  1243 			__SQLASSERT(aConfigParams.iSoftHeapLimitKb >= TSqlSrvConfigParams::KMinSoftHeapLimitKb && 
       
  1244 			            aConfigParams.iSoftHeapLimitKb <= TSqlSrvConfigParams::KMaxSoftHeapLimitKb, ESqlPanicInternalError);
       
  1245 	//Step 3: aConfigParams.iSoftHeapLimitKb value is set. Then use it to calculate the cache size. But we need the page size first.
       
  1246     //        aLogicalDbName is used instead of logicalDbName because PageSizeL() if called with non-zero length name, 
       
  1247 	//        "thinks" it is the main database name. KMainDb16 will be interpreted as an attached database name. 
       
  1248 		TInt pageSize = PageSizeL(aLogicalDbName);
       
  1249 	//Step 4: Calculate the cache size.
       
  1250 			TInt cacheSize = ((TInt64)aConfigParams.iSoftHeapLimitKb * 1024) / pageSize;//"TInt64" cast is used because of a possible overflow
       
  1251 	//Step 5: Set the cache size.
       
  1252 			__SQLLEAVE_IF_ERROR(::ExecPragma(iDbHandle, iAuthorizerDisabled, KCacheSizePragma, cacheSize, logicalDbName));
       
  1253 			}
       
  1254 		}
       
  1255 	}
       
  1256 
       
  1257 /**
       
  1258 Initializes the database compaction mode.
       
  1259 If the aCompactionMode parameter is ESqlCompactionBackground, the database with aDbFileName file name will be added
       
  1260 to the compactor for background compacting.
       
  1261 
       
  1262 @param aCompactionMode The database compaction mode. See TSqlCompactionMode enum for the supported database compaction modes.
       
  1263 @param aFreePageThresholdKb Free page threshold. The background compaction won't start if the free pages size in Kb is less than
       
  1264 						  the free page threshold.
       
  1265 @param aDbFileName Database file name including full path
       
  1266 @param aCurrentVacuumMode The current SQLite vacuum mode, one of TSqliteVacuumMode enum item values.
       
  1267 						  If the current database vacuum mode is ESqliteVacuumOff, which means 
       
  1268 						  the database has been created not by the SQL server, 
       
  1269 						  then the "off" vacuum mode is kept unchanged.
       
  1270 @param aDbName "main" or the attached database name
       
  1271 
       
  1272 @leave KErrNoMemory, an out of memory condition has occurred;
       
  1273                      Note that the function may also leave with some other database specific 
       
  1274                      errors categorised as ESqlDbError, and other system-wide error codes.
       
  1275 
       
  1276 @see TSqlCompactionMode
       
  1277 @see CSqlCompactor
       
  1278 @see TSqliteVacuumMode
       
  1279 
       
  1280 @panic SqlDb 4 In _DEBUG mode if aCompactionMode parameter value is invalid.
       
  1281 */
       
  1282 void CSqlSrvDatabase::InitCompactionL(TSqlCompactionMode aCompactionMode, TInt aFreePageThresholdKb, 
       
  1283 									  const TDesC& aDbFileName, TSqliteVacuumMode aCurrentVacuumMode, const TDesC& aDbName)
       
  1284 	{
       
  1285 	__SQLASSERT(aCompactionMode == ESqlCompactionManual || aCompactionMode == ESqlCompactionBackground || aCompactionMode == ESqlCompactionAuto, ESqlPanicBadArgument);
       
  1286 	__SQLASSERT(aCurrentVacuumMode == ESqliteVacuumOff || aCurrentVacuumMode == ESqliteVacuumAuto || 
       
  1287 			    aCurrentVacuumMode == ESqliteVacuumIncremental, ESqlPanicBadArgument);
       
  1288 	__SQLASSERT(aFreePageThresholdKb >= 0, ESqlPanicBadArgument);
       
  1289 	TSqliteVacuumMode newSqliteVacuumMode = aCompactionMode == ESqlCompactionAuto ? ESqliteVacuumAuto : ESqliteVacuumIncremental;
       
  1290 	if(aCurrentVacuumMode == ESqliteVacuumOff)
       
  1291 		{
       
  1292 		newSqliteVacuumMode = ESqliteVacuumOff;
       
  1293 		}
       
  1294 	if(aCurrentVacuumMode != newSqliteVacuumMode)	
       
  1295 		{
       
  1296 		__SQLLEAVE_IF_ERROR(::ExecPragma(iDbHandle, iAuthorizerDisabled, KAutoVacuumPragma, newSqliteVacuumMode, aDbName));
       
  1297 		}
       
  1298 	if(aCompactionMode == ESqlCompactionBackground)
       
  1299 		{
       
  1300 		NewCompactEntryL(aFreePageThresholdKb, aDbFileName, aDbName);
       
  1301 		}
       
  1302 	}
       
  1303 
       
  1304 /**
       
  1305 Adds the aDbFileName database to the compactor object for background compacting.
       
  1306 
       
  1307 @param aFreePageThresholdKb Free page threshold in Kb. The background compaction won't start if the total size of the free pages
       
  1308 						  is less than the free page threshold.
       
  1309 @param aDbFileName Database file name including full path
       
  1310 @param aDbName "main" or the attached database name
       
  1311 
       
  1312 @leave KErrNoMemory, an out of memory condition has occurred;
       
  1313                      Note that the function may also leave with some other database specific 
       
  1314                      errors categorised as ESqlDbError, and other system-wide error codes.
       
  1315 
       
  1316 @see CSqlCompactor
       
  1317 @see RSqlCompactDbMap 
       
  1318 */
       
  1319 void CSqlSrvDatabase::NewCompactEntryL(TInt aFreePageThresholdKb, const TDesC& aDbFileName, const TDesC& aDbName)
       
  1320 	{
       
  1321 	TSqlCompactSettings settings;
       
  1322 	settings.iFreePageThresholdKb = aFreePageThresholdKb;
       
  1323 	::SqlServer().Compactor().AddEntryL(aDbFileName, settings);
       
  1324 	TInt err = KErrNoMemory;
       
  1325 	HBufC* key = aDbName.Alloc();
       
  1326 	HBufC* data = aDbFileName.Alloc();
       
  1327 	if(key && data)
       
  1328 		{
       
  1329 		err = iCompactDbMap.Insert(key, data);//returns the index of the new entry
       
  1330 		}
       
  1331 	if(err < 0) //If either "key" or "data" or both is NULL, then "err" is KErrNoMemory and the next "if" will be executed.
       
  1332 		{
       
  1333 		delete data;
       
  1334 		delete key;
       
  1335 		::SqlServer().Compactor().ReleaseEntry(aDbFileName);
       
  1336 		}
       
  1337 	__SQLLEAVE_IF_ERROR(err);
       
  1338 	}
       
  1339 
       
  1340 /**
       
  1341 Removes database (identified by its logical name) from the compactor.
       
  1342 
       
  1343 @param aDbName "main" or the attached database name
       
  1344 
       
  1345 @see CSqlCompactor
       
  1346 @see RSqlCompactDbMap 
       
  1347 */
       
  1348 void CSqlSrvDatabase::ReleaseCompactEntry(const TDesC& aDbName)
       
  1349 	{
       
  1350 	TSqlCompactDbMapIterator compactDbIt(iCompactDbMap);
       
  1351 	TSqlCompactDbPair compactDbPair;
       
  1352 	while(compactDbIt.Next(compactDbPair))
       
  1353 		{
       
  1354 		if(::CompareNoCase(*compactDbPair.iKey, aDbName) == 0)
       
  1355 			{
       
  1356 			::SqlServer().Compactor().ReleaseEntry(*compactDbPair.iData);
       
  1357 			iCompactDbMap.Remove(compactDbPair.iKey);
       
  1358 			break;
       
  1359 			}
       
  1360 		}
       
  1361 	}
       
  1362 
       
  1363 /**
       
  1364 Cleanup function.
       
  1365 Used during the construction phase of the CSqlSrvDatabase instance when a new database is created.
       
  1366 If the database creation succeeds, the "init compaction" operation succeeds but some other init operation fail,
       
  1367 the just created database file has to be deleted. But before that the database has to be removed from the compactor,
       
  1368 because the compactor creates independent database connection that has to be closed before the database deletion.
       
  1369 
       
  1370 The database will be removed from the compactor as a result of the call.
       
  1371 
       
  1372 @param aCleanup A pointer to the CSqlSrvDatabase object
       
  1373 */
       
  1374 void CSqlSrvDatabase::CompactCleanup(void* aCleanup)
       
  1375 	{
       
  1376 	CSqlSrvDatabase* self = reinterpret_cast <CSqlSrvDatabase*> (aCleanup);
       
  1377 	__SQLASSERT(self != NULL, ESqlPanicBadArgument);
       
  1378 	if(self)
       
  1379 		{
       
  1380 		self->ReleaseCompactEntry(KMainDb16);
       
  1381 		}
       
  1382 	}
       
  1383 
       
  1384 /**
       
  1385 Retrieves the database page size.
       
  1386 If the request is for the main database page size and if the size is not retrieved yet, then the page size value will be 
       
  1387 cached in iPageSize data member.
       
  1388 
       
  1389 @param aDbName Attached database name or KNullDesC for the main database
       
  1390 
       
  1391 @leave KErrNoMemory, an out of memory condition has occurred;
       
  1392                       Note that the function may also leave with some other database specific 
       
  1393                       errors categorised as ESqlDbError, and other system-wide error codes.
       
  1394 
       
  1395 @return The database page size 
       
  1396 */
       
  1397 TInt CSqlSrvDatabase::PageSizeL(const TDesC& aDbName)
       
  1398 	{
       
  1399 	if(iPageSize > 0 && aDbName == KNullDesC)
       
  1400 		{
       
  1401 		return iPageSize;	
       
  1402 		}
       
  1403 	iAuthorizerDisabled	= ETrue;
       
  1404 	CleanupStack::PushL(TCleanupItem(&EnableAuthorizer, &iAuthorizerDisabled));
       
  1405 	TInt pageSize = 0;
       
  1406 	__SQLLEAVE_IF_ERROR(::DbPageSize(iDbHandle, aDbName, pageSize));
       
  1407 	CleanupStack::PopAndDestroy();
       
  1408 	__SQLASSERT(pageSize > 0, ESqlPanicInternalError);
       
  1409 	if(aDbName == KNullDesC)
       
  1410 		{
       
  1411 		iPageSize = pageSize;	
       
  1412 		}
       
  1413 	return pageSize;
       
  1414 	}
       
  1415 
       
  1416 //////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1417 /////////////////////////////        ConstructL() methods      ///////////////////////////////////////
       
  1418 //////////////////////////////////////////////////////////////////////////////////////////////////////
       
  1419 
       
  1420 /**
       
  1421 Second phase construction method. Creates a new secure database file.
       
  1422 If the function fails, the database file will be closed and deleted.
       
  1423 
       
  1424 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
  1425      			 file session reference and some other database file related properties.
       
  1426 				 If this is a secure database, then the format of the name must be:
       
  1427 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
  1428 				 If this is a non-secure database, then the file name has to be the full database file name.
       
  1429 				 "[SID]" refers to SID of the application which creates the database.
       
  1430 @param aSecurityPolicy Database security policy
       
  1431 
       
  1432 @panic SqlDb 4 In _DEBUG mode if aSecurityPolicy is NULL.
       
  1433 */
       
  1434 void CSqlSrvDatabase::ConstructCreateSecureL(const TSqlSrvFileData& aFileData, CSqlSecurityPolicy* aSecurityPolicy)
       
  1435 	{
       
  1436 	__SQLASSERT(aSecurityPolicy != NULL, ESqlPanicBadArgument);
       
  1437 	//Insert a new item in the security policies map.
       
  1438 	CleanupStack::PushL(aSecurityPolicy);
       
  1439 	const TUint8* mapKey = SecurityMapKeyL(aFileData.FileName());
       
  1440 	mapKey = ::CreateStrCopyLC(mapKey);
       
  1441 	__SQLLEAVE_IF_ERROR(::SqlServer().SecurityMap().Insert(mapKey, aSecurityPolicy));
       
  1442 	CleanupStack::Pop(2);//iSecurityMap owns mapKey and aSecurityPolicy.
       
  1443 	iSecureDbName = mapKey;
       
  1444 	iSecurityPolicy = aSecurityPolicy;
       
  1445 	//
       
  1446 	DoCommonConstructCreateL(aFileData, ETrue);
       
  1447 	}
       
  1448 
       
  1449 /**
       
  1450 Second phase construction method. Creates a new non-secure database file.
       
  1451 If the function fails, the database file will be closed and deleted.
       
  1452 
       
  1453 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
  1454      			 file session reference and some other database file related properties.
       
  1455 				 If this is a secure database, then the format of the name must be:
       
  1456 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
  1457 				 If this is a non-secure database, then the file name has to be the full database file name.
       
  1458 				 "[SID]" refers to SID of the application which creates the database.
       
  1459 */
       
  1460 void CSqlSrvDatabase::ConstructCreateL(const TSqlSrvFileData& aFileData)
       
  1461 	{
       
  1462 	DoCommonConstructCreateL(aFileData, EFalse);
       
  1463 	}
       
  1464 
       
  1465 //Called by the two "Contruct&Create" methods: ConstructCreateL() and ConstructCreateSecureL().
       
  1466 //The aSecureDb parameter tells which method is the caller.
       
  1467 //The function performs common construction and initialization:
       
  1468 // - creates the database file
       
  1469 // - makes the journal file persistent
       
  1470 // - initializes the database compaction mode
       
  1471 // - stores the initial settings in the settings table, including the current collation dll name
       
  1472 // - stores the security settings and installs the authorizer, if aSecureDb is true
       
  1473 // - installs the user-defined functions
       
  1474 // - installs collations
       
  1475 //If the method fails and the error is not KErrAlreadyExists, the database file will be closed and deleted.
       
  1476 void CSqlSrvDatabase::DoCommonConstructCreateL(const TSqlSrvFileData& aFileData, TBool aSecureDb)
       
  1477 	{
       
  1478 	__SQLASSERT(!iDbHandle, ESqlPanicInternalError);
       
  1479 	__SQLASSERT(aSecureDb ? iSecurityPolicy != NULL : ETrue, ESqlPanicInternalError);
       
  1480 	CreateNewDbFileL(aFileData);
       
  1481 	TDbFileCleanup dbFileCleanup(aFileData, iDbHandle);
       
  1482 	CleanupStack::PushL(TCleanupItem(&DbFileCleanup, &dbFileCleanup));
       
  1483 	//Make the journal file persistent - done by SQLite automatically because the locking mode is EXCLUSIVE
       
  1484 	//::ExecPragma(iDbHandle, iAuthorizerDisabled, KPersistentJournalPragma, KPersist);
       
  1485 	//Init database compaction mode
       
  1486 	TSqlCompactionMode compactionMode = aFileData.ConfigParams().iCompactionMode;
       
  1487 	if(compactionMode == ESqlCompactionNotSet)
       
  1488 		{
       
  1489 		compactionMode = KSqlDefaultCompactionMode;
       
  1490 		}
       
  1491 	TInt currVacuumMode = -1;
       
  1492 	__SQLLEAVE_IF_ERROR(::DbVacuumMode(iDbHandle, KNullDesC, currVacuumMode));
       
  1493 	//currVacuumMode == ESqliteVacuumOff ==> This is a database created not by the SQL server
       
  1494 	InitCompactionL(compactionMode, aFileData.ConfigParams().iFreePageThresholdKb, aFileData.FileName(), (TSqliteVacuumMode)currVacuumMode);
       
  1495 	CleanupStack::PushL(TCleanupItem(&CSqlSrvDatabase::CompactCleanup, this));
       
  1496 	//Store the initial settings in the settings table (including the current collation dll name)
       
  1497 	StoreSettingsL(::SqlServer().CollationDllName(), KSqlNullDbConfigFileVersion, compactionMode);
       
  1498 	if(aSecureDb)
       
  1499 		{
       
  1500 		//Store the security policies in the security policies tables.
       
  1501 		TSqlDbSysSettings dbSysSettings(iDbHandle);
       
  1502 		dbSysSettings.StoreSecurityPolicyL(*iSecurityPolicy);
       
  1503 		}
       
  1504 	InstallAuthorizerL();
       
  1505 	InstallUDFsL();
       
  1506 	InstallCollationsL();
       
  1507 	CleanupStack::Pop(2);//CompactCleanup, DbFileCleanup
       
  1508 	SQLPROFILER_DB_CREATE((TUint)iDbHandle, aFileData.FileName());
       
  1509 	}
       
  1510 
       
  1511 /**
       
  1512 Second phase construction method. Opens an existing  secure database file.
       
  1513 
       
  1514 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
  1515      			 file session reference and some other database file related properties.
       
  1516 				 If this is a secure database, then the format of the name must be:
       
  1517 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
  1518 				 If this is a non-secure database, then the file name has to be the full database file name.
       
  1519 				 "[SID]" refers to SID of the application which creates the database.
       
  1520 */
       
  1521 void CSqlSrvDatabase::ConstructOpenSecureL(const TSqlSrvFileData& aFileData)
       
  1522 	{
       
  1523 	DoCommonConstructOpenL(aFileData, ETrue);
       
  1524 	}
       
  1525 
       
  1526 /**
       
  1527 Second phase construction method. Opens an existing  non-secure database file.
       
  1528 
       
  1529 @param aFileData A reference to a TSqlSrvFileData instance, which keeps the database name, a
       
  1530      			 file session reference and some other database file related properties.
       
  1531 				 If this is a secure database, then the format of the name must be:
       
  1532 				 \<drive\>:\<[SID]database file name excluding the path\>.
       
  1533 				 If this is a non-secure database, then the file name has to be the full database file name.
       
  1534 				 "[SID]" refers to SID of the application which creates the database.
       
  1535 				 If this is application's private database, then the format of aFileData is as it is described
       
  1536 				 in TSqlSrvFileData::SetFromHandleL() comments.
       
  1537 @see TSqlSrvFileData::SetFromHandleL()
       
  1538 */
       
  1539 void CSqlSrvDatabase::ConstructOpenL(const TSqlSrvFileData& aFileData)
       
  1540 	{
       
  1541 	DoCommonConstructOpenL(aFileData, EFalse);
       
  1542 	}
       
  1543 
       
  1544 //Opens a database and does all necessary initializations
       
  1545 //Called by the two "Contruct&Open" methods: ConstructOpenL() and ConstructOpenSecureL().
       
  1546 //The aSecureDb parameter tells which method is the caller.
       
  1547 //The function performs common construction and initialization:
       
  1548 // - opens the database file
       
  1549 // - installs the user-defined functions
       
  1550 // - installs collations
       
  1551 // - installs the authoriser callback
       
  1552 void CSqlSrvDatabase::DoCommonConstructOpenL(const TSqlSrvFileData& aFileData, TBool aSecureDb)
       
  1553 	{
       
  1554 	OpenExistingDbFileL(aFileData);//iDbHandle is valid after a successful call
       
  1555 	//The user-defined collations must be installed before the possible database reindexing!!!
       
  1556 	InstallCollationsL();
       
  1557 	if(!aFileData.IsReadOnly())
       
  1558 		{//No need to disable the authorizer since it is not installed yet.
       
  1559 		 //Make sure that the user-defined collation have been installed before the reindexing operation.
       
  1560 		ProcessSettingsL(aFileData, KMainDb16);
       
  1561 		}
       
  1562 	if(aSecureDb)
       
  1563 		{
       
  1564 		const TUint8* mapKey = NULL;
       
  1565 		//Load database security policy, update the security policy map
       
  1566 		UpdateSecurityMapL(EFalse, aFileData, mapKey, iSecurityPolicy);
       
  1567 		mapKey = NULL;//it is not used
       
  1568 		//Check that the caller has at least one of {Schema, Read, Write} policies.
       
  1569 		BasicSecurityPolicyCheckL(*iSecurityPolicy);
       
  1570 		}
       
  1571 	//Install user-defined functions.
       
  1572 	InstallUDFsL();
       
  1573 	
       
  1574 	//Install the authorizer.
       
  1575 	InstallAuthorizerL();
       
  1576 	
       
  1577     SQLPROFILER_DB_OPEN((TUint)iDbHandle, aFileData.FileName());
       
  1578 	}
       
  1579 
       
  1580 /*
       
  1581 Implementation of the like() SQL function.  This function implements
       
  1582 the user defined LIKE operator.  The first argument to the function is the
       
  1583 pattern and the second argument is the string.  So, the SQL statements:
       
  1584 A LIKE B
       
  1585 is implemented as like(B, A).
       
  1586 
       
  1587 @param aContext Function call context;
       
  1588 @param aArgc Number of LIKE arguments: 2 for the standard LIKE operator, 3 for the LIKE operator with an ESCAPE clause;
       
  1589 @param aArgv LIKE arguments;
       
  1590 
       
  1591 @internalComponent
       
  1592 */
       
  1593 void CSqlSrvDatabase::LikeSqlFunc(sqlite3_context* aContext, int aArgc, sqlite3_value** aArgv)
       
  1594 	{
       
  1595   	TUint escapeChar = 0;
       
  1596 	if(aArgc == 3)
       
  1597 		{
       
  1598     	//The escape character string must consist of a single UTF16 character.
       
  1599     	//Otherwise, return an error.
       
  1600 		const TUint16* esc = static_cast <const TUint16*> (sqlite3_value_text16(aArgv[2]));
       
  1601 		if(!esc)
       
  1602 			{
       
  1603       		sqlite3_result_error(aContext, KErrMsg1, -1);
       
  1604 			return;
       
  1605 			}
       
  1606 		if(User::StringLength(esc) != 1)
       
  1607 			{
       
  1608       		sqlite3_result_error(aContext, KErrMsg2, -1);
       
  1609           	return;
       
  1610 			}
       
  1611 		escapeChar = *esc;			
       
  1612     	}
       
  1613 	const TUint16* pattern   = static_cast <const TUint16*> (sqlite3_value_text16(aArgv[0]));
       
  1614 	const TUint16* candidate = static_cast <const TUint16*> (sqlite3_value_text16(aArgv[1]));
       
  1615   	if(pattern && candidate)
       
  1616 		{
       
  1617 		TInt wildChar = '_';
       
  1618 		TInt wildSeqChar = '%';
       
  1619 		TPtrC16 patternStr(pattern, (TUint)sqlite3_value_bytes16(aArgv[0]) / sizeof(TUint16));
       
  1620 		TPtrC16 candidateStr(candidate, (TUint)sqlite3_value_bytes16(aArgv[1]) / sizeof(TUint16));
       
  1621 		TInt res = candidateStr.MatchC(patternStr, wildChar, wildSeqChar, escapeChar, 0/*collation level*/);
       
  1622     	sqlite3_result_int(aContext, res >= 0);
       
  1623 		//RDebug::Print(_L("--res=%d, pattern=%S, candidate=%S\r\n"), res, &patternStr, &candidateStr);
       
  1624 		}
       
  1625 	}
       
  1626