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