persistentstorage/sql/SRC/Server/SqlSrvStatementUtil.cpp
changeset 0 08ec8eefde2f
child 9 667e88a979d7
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <e32debug.h>
       
    17 #include <hal.h>
       
    18 #include <sqldb.h>
       
    19 #include "sqlite3.h"
       
    20 #include "SqlSrvStatementUtil.h"
       
    21 #include "SqlPanic.h"
       
    22 #include "SqlSrvUtil.h"
       
    23 #include "SqlUtil.h"
       
    24 #include "SqliteSymbian.h"		//sqlite3SymbianLastOsError()
       
    25 #include "SqlSrvResourceProfiler.h"
       
    26 
       
    27 //The database names in all statements are quoted to avoid the "sql injection" threat.
       
    28 _LIT8(KPageCountPragma, "PRAGMA \"%S\".page_count\x0");
       
    29 _LIT8(KPageSizePragma,  "PRAGMA \"%S\".page_size\x0");
       
    30 _LIT8(KCacheSizePragma,  "PRAGMA \"%S\".cache_size\x0");
       
    31 _LIT8(KEncodingPragma,  "PRAGMA \"%S\".encoding\x0");
       
    32 _LIT8(KFreePageCountPragma, "PRAGMA \"%S\".freelist_count\x0");
       
    33 _LIT8(KVacuumModePragma, "PRAGMA \"%S\".auto_vacuum\x0");
       
    34 _LIT8(KIncrementalVacuumPragma, "PRAGMA \"%S\".incremental_vacuum(%d)\x0");
       
    35 
       
    36 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
    37 
       
    38 #ifdef _NOTIFY
       
    39 static void PrintErrMsg8(TBool aCondition, sqlite3* aDbHandle, const char* aFuncNameZ, const TDesC8& aStmt)
       
    40 	{
       
    41 	if(!aCondition)
       
    42 		{
       
    43 		return;	
       
    44 		}
       
    45 	TPtrC8 funcName8(reinterpret_cast <const TUint8*> (aFuncNameZ));
       
    46 	TBuf<32> funcName;
       
    47 	funcName.Copy(funcName8);
       
    48 	RDebug::Print(_L("###%S\r\n"), &funcName);
       
    49 	TInt stmtLen = aStmt.Length();
       
    50 	if(stmtLen > 0)
       
    51 		{
       
    52 		if(aStmt[stmtLen - 1] == 0)
       
    53 			{
       
    54 			--stmtLen;
       
    55 			}
       
    56 		HBufC* buf = HBufC::New(stmtLen);
       
    57 		if(buf)
       
    58 			{
       
    59 			TPtr sqlStmt = buf->Des();
       
    60 			sqlStmt.Copy(aStmt.Left(stmtLen));
       
    61 			if(sqlStmt.Length() > 250)
       
    62 				{
       
    63 				sqlStmt.SetLength(250);		
       
    64 				}
       
    65 			RDebug::Print(_L("###\"%S\"\r\n"), &sqlStmt);
       
    66 			delete buf;
       
    67 			}
       
    68 		}
       
    69 	TBuf<16> tbuf;
       
    70 	Util::GetTimeStr(tbuf);
       
    71 	const void* errMsg = sqlite3_errmsg16(aDbHandle);//"errMsg" - zero terminated string
       
    72 	if(errMsg)
       
    73 		{
       
    74 		TPtrC msg(reinterpret_cast <const TText16*> (errMsg));//terminating zero character excluded.
       
    75 		if(msg.Length() > 230)
       
    76 			{
       
    77 			msg.Set(msg.Left(230));		
       
    78 			}
       
    79 		RDebug::Print(_L("##%S#ErrMsg=%S\r\n"), &tbuf, &msg);
       
    80 		}
       
    81 	else
       
    82 		{
       
    83 		RDebug::Print(_L("##%S#ErrMsg=null\r\n"), &tbuf);
       
    84 		}
       
    85 	}
       
    86 	
       
    87 static void PrintErrMsg16(TBool aCondition, sqlite3* aDbHandle, const char* aFuncNameZ, const TDesC16& aStmt)
       
    88 	{
       
    89 	if(!aCondition)
       
    90 		{
       
    91 		return;	
       
    92 		}
       
    93 	TPtrC8 funcName8(reinterpret_cast <const TUint8*> (aFuncNameZ));
       
    94 	TBuf<32> funcName;
       
    95 	funcName.Copy(funcName8);
       
    96 	RDebug::Print(_L("###%S\r\n"), &funcName);
       
    97 	TInt stmtLen = aStmt.Length();
       
    98 	if(stmtLen > 0)
       
    99 		{
       
   100 		if(aStmt[stmtLen - 1] == 0)
       
   101 			{
       
   102 			--stmtLen;
       
   103 			}
       
   104 		TPtrC sqlStmt(aStmt.Ptr(), stmtLen);
       
   105 		if(sqlStmt.Length() > 250)
       
   106 			{
       
   107 			sqlStmt.Set(sqlStmt.Left(250));		
       
   108 			}
       
   109 		RDebug::Print(_L("###\"%S\"\r\n"), &sqlStmt);
       
   110 		}
       
   111 	TBuf<16> tbuf;
       
   112 	Util::GetTimeStr(tbuf);
       
   113 	const void* errMsg = sqlite3_errmsg16(aDbHandle);//"errMsg" - zero terminated string
       
   114 	if(errMsg)
       
   115 		{
       
   116 		TPtrC msg(reinterpret_cast <const TText16*> (errMsg));//terminating zero character excluded.
       
   117 		if(msg.Length() > 230)
       
   118 			{
       
   119 			msg.Set(msg.Left(230));		
       
   120 			}
       
   121 		RDebug::Print(_L("##%S#ErrMsg=%S\r\n"), &tbuf, &msg);
       
   122 		}
       
   123 	else
       
   124 		{
       
   125 		RDebug::Print(_L("##%S#ErrMsg=null\r\n"), &tbuf);
       
   126 		}
       
   127 	}
       
   128 
       
   129 #define PRINT_ERRMSG8(Condition, DbHandle, FuncNameZ, Stmt) PrintErrMsg8(Condition, DbHandle, FuncNameZ, Stmt)
       
   130 #define PRINT_ERRMSG16(Condition, DbHandle, FuncNameZ, Stmt) PrintErrMsg16(Condition, DbHandle, FuncNameZ, Stmt)
       
   131 
       
   132 #else  //_NOTIFY
       
   133 
       
   134 #define PRINT_ERRMSG8(Condition, DbHandle, FuncNameZ, Stmt) 
       
   135 #define PRINT_ERRMSG16(Condition, DbHandle, FuncNameZ, Stmt) 
       
   136 	
       
   137 #endif //_NOTIFY
       
   138 
       
   139 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   140 
       
   141 //Calls sqlite3_open16() to create or open database file with aFileNameZ.
       
   142 //aFileNameZ is UTF16 encoded, zero-terminated.
       
   143 //The function returns system-wide errors or database specific errors.
       
   144 //The function may panic with code 7 in _DEBUG mode - internal error: the created database handle is NULL.
       
   145 TInt CreateDbHandle16(const TDesC& aFileNameZ, sqlite3*& aDbHandle)
       
   146 	{
       
   147 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   148 	TInt err = sqlite3_open16(aFileNameZ.Ptr(), &aDbHandle);
       
   149 	__SQLASSERT(err == SQLITE_OK ? aDbHandle != NULL : ETrue, ESqlPanicInternalError);
       
   150 	if(err == SQLITE_OK)
       
   151 		{
       
   152 		(void)sqlite3_extended_result_codes(aDbHandle, 0);
       
   153 		}
       
   154 	//Get the return error code now, because the next "if" may destroy it.
       
   155 	TInt rc = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   156 	if(err != SQLITE_OK)
       
   157 		{//Yes, it is possible error code != SQLITE_OK and aDbHandle != NULL.
       
   158 		CloseDbHandle(aDbHandle);
       
   159 		aDbHandle = NULL;
       
   160 		}
       
   161 	return rc;
       
   162 	}
       
   163 
       
   164 //Calls sqlite3_open() to create or open database file with aFileNameZ.
       
   165 //aFileNameZ is UTF8 encoded, zero-terminated.
       
   166 //The function returns system-wide errors or database specific errors.
       
   167 //The function may panic with code 7 in _DEBUG mode - internal error: the created database handle is NULL.
       
   168 TInt CreateDbHandle8(const TDesC8& aFileNameZ, sqlite3*& aDbHandle)
       
   169 	{
       
   170 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   171 	TInt err = sqlite3_open((const char *) aFileNameZ.Ptr(), &aDbHandle);
       
   172 	__SQLASSERT(err == SQLITE_OK ? aDbHandle != NULL : ETrue, ESqlPanicInternalError);
       
   173 	if(err == SQLITE_OK)
       
   174 		{
       
   175 		(void)sqlite3_extended_result_codes(aDbHandle, 0);
       
   176 		}
       
   177 	//Get the return error code now, because the next "if" may destroy it.
       
   178 	TInt rc = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   179 	if(err != SQLITE_OK)
       
   180 		{//Yes, it is possible error code != SQLITE_OK and aDbHandle != NULL.
       
   181 		CloseDbHandle(aDbHandle);
       
   182 		aDbHandle = NULL;
       
   183 		}
       
   184 	return rc;
       
   185 	}
       
   186 	
       
   187 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   188 /////                     16-bit and 8-bit SQL statements execution upon completion                        ////
       
   189 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   190 
       
   191 //16-bit SQL statement execution.
       
   192 //
       
   193 //aSql - zero-terminated string
       
   194 //
       
   195 //Prepares the supplied as an argument (aSql) 16-bit SQL statement and executes it.
       
   196 //If aSql argument contains more than one SQL statements, separated with ';', then
       
   197 //the function panics in _DEBUG mode (panic code 7).
       
   198 //
       
   199 //The function panics in debug mode (panic code 2) if aDbHandle is NULL.
       
   200 //
       
   201 //If the function completes successfully, it returns SQLITE_ROW or SQLITE_DONE.
       
   202 //If the function fails then it returns one of the SQLITE error codes.
       
   203 static TInt DoSingleStmtExec16(sqlite3 *aDbHandle, const TDesC16& aSql)
       
   204 	{
       
   205 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInvalidObj);
       
   206 	sqlite3_stmt* stmtHandle = NULL;
       
   207 	const void* stmtTail = NULL;
       
   208 	//sqlite3_prepare16_v2() expects parameter #3 to be one of the following:
       
   209 	// - byte length of the sql statement, excluding terminating zero;
       
   210 	// - negative value - zero-terminated sql statement;
       
   211 	TInt err = sqlite3_prepare16_v2(aDbHandle, aSql.Ptr(), aSql.Length() * sizeof(TUint16) - sizeof(TUint16), &stmtHandle, &stmtTail);
       
   212 	__SQLASSERT(err == SQLITE_OK ? !stmtTail || User::StringLength((const TUint16*)stmtTail) == 0 : !stmtHandle, ESqlPanicInternalError);
       
   213 	if(stmtHandle)	//stmtHandle can be NULL for statements like this: ";".
       
   214 		{
       
   215 		if(err == SQLITE_OK)
       
   216 			{
       
   217 			while((err = sqlite3_step(stmtHandle)) == SQLITE_ROW)
       
   218 				{
       
   219 				}
       
   220 			if(err == SQLITE_ERROR)	//It may be "out of memory" problem
       
   221 				{
       
   222 				err = sqlite3_reset(stmtHandle);
       
   223 				__SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError);
       
   224 				}
       
   225 			}
       
   226 		TInt err2 = sqlite3_finalize(stmtHandle);
       
   227 		if(err == SQLITE_DONE && err2 != SQLITE_OK)
       
   228 			{//return the "sqlite3_finalize" error
       
   229 			err = err2;	
       
   230 			}
       
   231 		}
       
   232 	return err;
       
   233 	}
       
   234 
       
   235 /**
       
   236 This function searches aString argument for ';' occurences.
       
   237 Every time when it finds a ';' character, the function places a zero character right after the ';' and
       
   238 tests the just created, zero-terminated substring if it is a comlpete SQL statement.
       
   239 
       
   240 If it is a SQL statement, the function replaces the found ';' character with zero and returns the just created
       
   241 zero-terminated substring.Also the function modifies aString argument to point right after the found
       
   242 SQL string. If it is not SQL statement, the function will continue the searching.
       
   243 
       
   244 If there is no ';' inside aString argument, the function returns the same string as a return result and
       
   245 modifies aString argument - sets it to TPtr(NULL, 0, 0).
       
   246 
       
   247 The function expects aString argument to be zero-terminated.
       
   248 
       
   249 @internalComponent
       
   250 */
       
   251 TPtrC GetFirstSqlStmt(TPtr& aString)
       
   252 	{
       
   253 	const TChar KDelimitier(';');
       
   254 	TPtr originalStr(aString);
       
   255 	TPtr str(const_cast <TUint16*> (aString.Ptr()), aString.Length(), aString.Length());
       
   256 	TInt afterDelimitierPos = 0;
       
   257 	TInt pos;
       
   258 	while((pos = str.Locate(KDelimitier) + 1) > 0 && pos < str.Length())
       
   259 		{
       
   260 		//There is a possibility that the string, which terminates with the found ';' character, is a SQL statement.
       
   261 		//Zero terminate the string placing a zero right after the ';' character and test it using sqlite3_complete16().
       
   262 		//If it is not a SQL string, restore the original character and continue searching.
       
   263 		afterDelimitierPos += pos;
       
   264 		TChar ch = aString[afterDelimitierPos];
       
   265 		aString[afterDelimitierPos] = 0;
       
   266 		TInt res = sqlite3_complete16(aString.Ptr());
       
   267 		aString[afterDelimitierPos] = ch;
       
   268 		if(res)
       
   269 			{
       
   270 			str.Set(const_cast <TUint16*> (aString.Ptr()), afterDelimitierPos, afterDelimitierPos);	
       
   271 			//Replace the found ';' character with 0.
       
   272 			str[afterDelimitierPos - 1] = 0;
       
   273 			aString.Set(const_cast <TUint16*> (aString.Ptr()) + afterDelimitierPos, aString.Length() - afterDelimitierPos, aString.Length() - afterDelimitierPos);
       
   274 			return str;
       
   275 			}
       
   276 		str.Set(const_cast <TUint16*> (str.Ptr()) + pos, str.Length() - pos, str.Length() - pos);	
       
   277 		}
       
   278 	//aString argument does not contain valid SQL statement or there is no ';' character inside aString.
       
   279 	//Set aString to TPtr(NULL, 0, 0) and return the original string.
       
   280 	aString.Set(NULL, 0, 0);
       
   281 	str.Set(originalStr);
       
   282 	return str;
       
   283 	}
       
   284 
       
   285 /**
       
   286 Executes one or more 16-bit SQL statements. SQL statements of any kind can be executed, but the 
       
   287 method won't return any record(s) if the SQL statement type is "SELECT".
       
   288 If the SQL statement(s) contains one or more parameters, the method will execute it giving the parameters
       
   289 default NULL values.
       
   290 
       
   291 @param aDbHandle Database handle. Not NULL.
       
   292 @param aSqlStmt String containing one or more 16-bit SQL statements, separated with ';'. Zero-terminated string.
       
   293 				Note: The ExecL() call can modify the content of aSqlStmt argument.
       
   294 
       
   295 @return KErrNone, Operation completed successfully;
       
   296 		KErrNoMemory, Out of memory;
       
   297 		KSqlErrGeneral, Syntax error. A text message describing the problem can be obtained calling
       
   298 						RSqlDatabase::LastErrorMessage();
       
   299 						Other system-wide error codes or SQL errors of ESqlDbError type.
       
   300 
       
   301 @panic SqlDb 4 In _DEBUG mode if aSqlStmt is not zero-terminated string
       
   302 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   303 
       
   304 @internalComponent
       
   305 */
       
   306 TInt DbExecStmt16(sqlite3 *aDbHandle, TDes16& aSqlStmt)
       
   307 	{
       
   308 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   309 	__SQLASSERT(aSqlStmt.Length() > 0 ? (TInt)aSqlStmt[aSqlStmt.Length() - 1] == 0: ETrue, ESqlPanicBadArgument);
       
   310 
       
   311 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   312 	
       
   313 	TInt err = SQLITE_DONE;
       
   314 	//Execute SQL statement(s)
       
   315 	//16-bit SQL string - no sqlite3_exec16() function, so the execution is made with 
       
   316 	//sqlite3_prepare16_v2() and sqlite3_step() functions.
       
   317 	TPtr16 sql(const_cast <TUint16*> (aSqlStmt.Ptr()), aSqlStmt.Length(), aSqlStmt.Length());
       
   318 	TPtrC firstSqlStmt(KNullDesC);
       
   319 	while(err == SQLITE_DONE && sql.Length() > 1) //"> 1" because it is a zero terminated string
       
   320 		{
       
   321 		firstSqlStmt.Set(GetFirstSqlStmt(sql));
       
   322         SQLPROFILER_SQL16_PRINT((TUint)aDbHandle, firstSqlStmt.Left(firstSqlStmt.Length() - 1), EFalse);
       
   323 		err = ::DoSingleStmtExec16(aDbHandle, firstSqlStmt);
       
   324 		}
       
   325 		
       
   326 	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   327 	if(err == KSqlAtEnd)
       
   328 		{
       
   329 		err = KErrNone;	
       
   330 		}
       
   331 	PRINT_ERRMSG16(err <= KSqlErrGeneral, aDbHandle, "DbExecStmt16()", aSqlStmt);
       
   332 	return err;
       
   333 	}
       
   334 
       
   335 /**
       
   336 Executes one or more 8-bit SQL statements. SQL statements of any kind can be executed, but the 
       
   337 method won't return any record(s) if the SQL statement type is "SELECT".
       
   338 If the SQL statement(s) contains one or more parameters, the method will execute it giving the parameters
       
   339 default NULL values.
       
   340 
       
   341 @param aDbHandle Database handle. Not NULL.
       
   342 @param aSqlStmt String containing one or more 8-bit SQL statements, separated with ';'. Zero-terminated string.
       
   343 
       
   344 @return KErrNone, Operation completed successfully;
       
   345 		KErrNoMemory, Out of memory;
       
   346 		KSqlErrGeneral, Syntax error. A text message describing the problem can be obtained calling
       
   347 						RSqlDatabase::LastErrorMessage();
       
   348 		Other system-wide error codes or SQL errors of ESqlDbError type.
       
   349 
       
   350 @panic SqlDb 4 In _DEBUG mode if aSqlStmt is not zero-terminated string
       
   351 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   352 
       
   353 @internalComponent
       
   354 */
       
   355 TInt DbExecStmt8(sqlite3 *aDbHandle, const TDesC8& aSqlStmt)
       
   356 	{
       
   357 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   358 	__SQLASSERT(aSqlStmt.Length() > 0 ? (TInt)aSqlStmt[aSqlStmt.Length() - 1] == 0: ETrue, ESqlPanicBadArgument);
       
   359 
       
   360     SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), EFalse);
       
   361 	
       
   362 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   363 	
       
   364 	TInt err = sqlite3_exec(aDbHandle, reinterpret_cast <const char*> (aSqlStmt.Ptr()), NULL, NULL, NULL);
       
   365 
       
   366 	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   367 	if(err == KSqlAtEnd)
       
   368 		{
       
   369 		err = KErrNone;	
       
   370 		}
       
   371 	PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "DbExecStmt8()", aSqlStmt);
       
   372 	return err;
       
   373 	}
       
   374 
       
   375 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   376 /////                     16-bit and 8-bit SQL statement preparation                                      /////
       
   377 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
       
   378 
       
   379 //Prepares 16-bit SQL statement, returning in aStmtHandle the statement handle and
       
   380 //setting aHasTail to true, if aStmt contains more than one sql statements.
       
   381 //aStmt - zero-terminated string.
       
   382 //Returns one of SQLITE error codes.
       
   383 static TInt DoPrepareStmt16(sqlite3* aDbHandle, const TDesC& aStmt, sqlite3_stmt** aStmtHandle, TBool& aHasTail)
       
   384 	{
       
   385 	const void* stmtTail = NULL;
       
   386 	//sqlite3_prepare16_v2() expects parameter #3 to be one of the following:
       
   387 	// - byte length of the sql statement, excluding terminating zero;
       
   388 	// - negative value - zero-terminated sql statement;
       
   389 	TInt err = sqlite3_prepare16_v2(aDbHandle, aStmt.Ptr(), aStmt.Length() * sizeof(TUint16) - sizeof(TUint16), aStmtHandle, &stmtTail);
       
   390 	aHasTail = stmtTail && static_cast <const TUint16*> (stmtTail)[0] != 0;
       
   391 	PRINT_ERRMSG16(err != SQLITE_OK, aDbHandle, "DoPrepareStmt16()", aStmt);
       
   392 	__SQLASSERT(err != SQLITE_OK ? !(*aStmtHandle) : ETrue, ESqlPanicInternalError);
       
   393 	//(*aStmtHandle) is NULL for ";" statements, when err == SQLITE_OK. Since the server should not panic
       
   394 	//that situation is handled later (not inside the assert above)
       
   395 	return err;
       
   396 	}
       
   397 	
       
   398 //Prepares 8-bit SQL statement, returning in aStmtHandle the statement handle and
       
   399 //setting aHasTail to true, if aStmt contains more than one sql statements.
       
   400 //aStmt - zero-terminated string.
       
   401 //Returns one of SQLITE error codes.
       
   402 static TInt DoPrepareStmt8(sqlite3* aDbHandle, const TUint8* aStmt, sqlite3_stmt** aStmtHandle, TBool& aHasTail)
       
   403 	{
       
   404 	const char* stmtTail = NULL;
       
   405 	//sqlite3_prepare_v2() expects parameter #3 to be one of the following:
       
   406 	// - byte length of the sql statement;
       
   407 	// - negative value - zero-terminated sql statement;
       
   408 	TInt err = sqlite3_prepare_v2(aDbHandle, reinterpret_cast <const char*> (aStmt), -1, aStmtHandle, &stmtTail);
       
   409 	aHasTail = stmtTail && stmtTail[0] != 0;
       
   410 	PRINT_ERRMSG8(err != SQLITE_OK, aDbHandle, "DoPrepareStmt8()", TPtrC8(aStmt, aStmt ? User::StringLength(aStmt) : 0));
       
   411 	__SQLASSERT(err != SQLITE_OK ? !(*aStmtHandle) : ETrue, ESqlPanicInternalError);
       
   412 	//(*aStmtHandle) is NULL for ";" statements, when err == SQLITE_OK. Since the server should not panic
       
   413 	//that situation is handled later (not inside the assert above)
       
   414 	return err;
       
   415 	}
       
   416 
       
   417 //This function accepts as arguments the SQLITE error, the length of non-parsed part of the SQL statement
       
   418 //and the statement handle.
       
   419 //
       
   420 //It checks the arguments and returns an error if:
       
   421 // - aSqliteError != SQLITE_OK;
       
   422 // - aHasTail is true (possibly more than one SQL statement, separated with ";");
       
   423 // - aStmtHandle is NULL;
       
   424 //
       
   425 static TInt ProcessPrepareError(TInt aSqliteError, TBool aHasTail, sqlite3_stmt* aStmtHandle)
       
   426 	{
       
   427 	if(aSqliteError != SQLITE_OK)
       
   428 		{
       
   429 		return ::Sql2OsErrCode(aSqliteError, sqlite3SymbianLastOsError());
       
   430 		}
       
   431 	else if(aHasTail || !aStmtHandle)
       
   432 		{//More than one SQL statement or the SQL string is "" or ";;;" or ";   ;; ;". 
       
   433 		 //Report it as an error, because there is no statement handle.
       
   434 		return KErrArgument;
       
   435 		}
       
   436 	return KErrNone;
       
   437 	}
       
   438 
       
   439 //This function accepts as arguments the SQLITE error, the length of non-parsed part of the SQL statement
       
   440 //and the statement handle.
       
   441 //
       
   442 //It checks the arguments and leaves if:
       
   443 // - aSqliteError != SQLITE_OK;
       
   444 // - aHasTail is true (possibly more than one SQL statement, separated with ";");
       
   445 // - aStmtHandle is NULL;
       
   446 //
       
   447 static void LeaveIfPrepareErrorL(TInt aSqliteError, TBool aHasTail, sqlite3_stmt* aStmtHandle)
       
   448 	{
       
   449 	__SQLLEAVE_IF_ERROR(ProcessPrepareError(aSqliteError, aHasTail, aStmtHandle));
       
   450 	}
       
   451 
       
   452 /**
       
   453 Prepares 16-bit aSqlStmt SQL statement.
       
   454 
       
   455 @param aSqlStmt - zero-terminated string.
       
   456 
       
   457 @leave KErrNoMemory, if there is no memory;
       
   458 	   KErrArgument, if the SQL string contains more than one SQL statements;
       
   459 	   One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range.
       
   460 
       
   461 @return The prepared SQL statement handle.
       
   462 
       
   463 @internalComponent
       
   464 */
       
   465 sqlite3_stmt* StmtPrepare16L(sqlite3* aDbHandle, const TDesC16& aSqlStmt)
       
   466 	{
       
   467     SQLPROFILER_SQL16_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue);
       
   468 	
       
   469 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   470 	TBool hasTail = EFalse;
       
   471 	sqlite3_stmt* stmtHandle = NULL;
       
   472 	TInt err = DoPrepareStmt16(aDbHandle, aSqlStmt, &stmtHandle, hasTail);
       
   473 	LeaveIfPrepareErrorL(err, hasTail, stmtHandle);
       
   474 	return stmtHandle;
       
   475 	}
       
   476 
       
   477 /**
       
   478 Prepares 8-bit aSqlStmt SQL statement.
       
   479 
       
   480 @param aSqlStmt - zero-terminated string.
       
   481 
       
   482 @leave KErrNoMemory, if there is no memory;
       
   483 	   KErrArgument, if the SQL string contains more than one SQL statements;
       
   484 	   One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range.
       
   485 
       
   486 @return The prepared SQL statement handle.
       
   487 
       
   488 @internalComponent
       
   489 */
       
   490 TInt StmtPrepare8(sqlite3* aDbHandle, const TDesC8& aSqlStmt, sqlite3_stmt*& aStmtHandle)
       
   491 	{
       
   492     SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue);
       
   493 	
       
   494 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   495 	TBool hasTail = EFalse;
       
   496 	TInt err = DoPrepareStmt8(aDbHandle, aSqlStmt.Ptr(), &aStmtHandle, hasTail);
       
   497 	return ProcessPrepareError(err, hasTail, aStmtHandle);
       
   498 	}
       
   499 
       
   500 /**
       
   501 Prepares 8-bit aSqlStmt SQL statement.
       
   502 
       
   503 @param aSqlStmt - zero-terminated string.
       
   504 
       
   505 @leave KErrNoMemory, if there is no memory;
       
   506 	   KErrArgument, if the SQL string contains more than one SQL statements;
       
   507 	   One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range.
       
   508 
       
   509 @return The prepared SQL statement handle.
       
   510 
       
   511 @internalComponent
       
   512 */
       
   513 sqlite3_stmt* StmtPrepare8L(sqlite3* aDbHandle, const TDesC8& aSqlStmt)
       
   514 	{
       
   515     SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue);
       
   516 	
       
   517 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   518 	TBool hasTail = EFalse;
       
   519 	sqlite3_stmt* stmtHandle = NULL;
       
   520 	TInt err = DoPrepareStmt8(aDbHandle, aSqlStmt.Ptr(), &stmtHandle, hasTail);
       
   521 	LeaveIfPrepareErrorL(err, hasTail, stmtHandle);
       
   522 	return stmtHandle;
       
   523 	}
       
   524 
       
   525 /**
       
   526 Executes upon completion the prepared SQL statement.
       
   527 
       
   528 @param aStmtHandle Prepared statement handle
       
   529 
       
   530 @return KSqlErrStmtExpired, Statement expired (if new functions or collating sequences are 
       
   531 							registered or if an authorizer function is added or changed);
       
   532 		KErrNoMemory, Out of memory. The statement will be reset;
       
   533 		KErrNone, The reset operation completed successfully.							
       
   534 
       
   535 @panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle.
       
   536 @panic SqlDb 7 In _DEBUG mode. SQLITE internal error. (SQLITE_ERROR, followed by a sqlite3_reset(), which returns SQLITE_OK)
       
   537 
       
   538 @internalComponent
       
   539 */	
       
   540 TInt StmtExec(sqlite3_stmt* aStmtHandle)
       
   541 	{
       
   542 	__SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj);
       
   543 	
       
   544 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   545 	
       
   546 	if(sqlite3_expired(aStmtHandle))
       
   547 		{
       
   548 		return KSqlErrStmtExpired;
       
   549 		}
       
   550 		
       
   551 	TInt err;
       
   552 	while((err = sqlite3_step(aStmtHandle)) == SQLITE_ROW)
       
   553 		{
       
   554 		}
       
   555 		
       
   556 	if(err == SQLITE_ERROR)	//It may be "out of memory" problem
       
   557 		{
       
   558 		err = sqlite3_reset(aStmtHandle);
       
   559 		__SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError);
       
   560 		}
       
   561 		
       
   562 	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   563 	if(err == KSqlAtEnd)
       
   564 		{
       
   565 		err = KErrNone;	
       
   566 		}
       
   567 
       
   568 	PRINT_ERRMSG16(err <= KSqlErrGeneral, sqlite3_db_handle(aStmtHandle), "StmtExec()", _L(" "));
       
   569 	return err;
       
   570 	}
       
   571 
       
   572 /**
       
   573 Executes the SQL statement moving it to the next row if available.
       
   574 
       
   575 @return KSqlErrStmtExpired Statement expired (if new functions or collating sequences are 
       
   576 							registered or if an authorizer function is added or changed)
       
   577 @return KSqlAtRow, The next record data is ready for processing by the caller;
       
   578 		KSqlAtEnd, No more record data;
       
   579 		KSqlErrBusy, Database file is locked;
       
   580 		KSqlErrGeneral, Run-time error. Next() should not be called anymore;
       
   581 		KSqlErrMisuse, Next() called after KSqlAtEnd or KSqlErrGeneral returned by the previous Next() call;
       
   582 		KErrNoMemory, Out of memory. The statement will be reset.
       
   583 
       
   584 @panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle.
       
   585 @panic SqlDb 7 In _DEBUG mode. SQLITE internal error. (SQLITE_ERROR, followed by a sqlite3_reset(), which returns SQLITE_OK)
       
   586 
       
   587 @internalComponent
       
   588 */	
       
   589 TInt StmtNext(sqlite3_stmt* aStmtHandle)
       
   590 	{
       
   591 	__SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj);
       
   592 	
       
   593 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   594 	
       
   595 	if(sqlite3_expired(aStmtHandle))
       
   596 		{
       
   597 		return KSqlErrStmtExpired;
       
   598 		}
       
   599 		
       
   600 	TInt err = sqlite3_step(aStmtHandle);
       
   601 	if(err == SQLITE_ERROR)	//It may be "out of memory" problem
       
   602 		{
       
   603 		err = sqlite3_reset(aStmtHandle);
       
   604 		__SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError);
       
   605 		}
       
   606 	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   607 	PRINT_ERRMSG16(err <= KSqlErrGeneral, sqlite3_db_handle(aStmtHandle), "StmtNext()", _L(" "));
       
   608 	return err;
       
   609 	}
       
   610 
       
   611 /**
       
   612 Resets the prepared SQL statement to its initial state and makes it ready to be executed again.
       
   613 Any SQL statement parameters that had values bound to them, retain their values.
       
   614 
       
   615 @return KSqlErrStmtExpired, Statement expired (if new functions or collating sequences are 
       
   616 							registered or if an authorizer function is added or changed);
       
   617 		KErrNone, The reset operation completed successfully.							
       
   618 
       
   619 @panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle.
       
   620 
       
   621 @internalComponent
       
   622 */	
       
   623 TInt StmtReset(sqlite3_stmt* aStmtHandle)
       
   624 	{
       
   625 	__SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj);
       
   626 	
       
   627 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   628 	
       
   629 	if(sqlite3_expired(aStmtHandle))
       
   630 		{
       
   631 		return KSqlErrStmtExpired;
       
   632 		}
       
   633 		
       
   634 	TInt err = sqlite3_reset(aStmtHandle);
       
   635 	return ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   636 	}
       
   637 
       
   638 /**
       
   639 Prepares and executes PRAGMA statement and moves the statement cursor on the first row.
       
   640 
       
   641 @param aDbHandle Database handle
       
   642 @param aDbName Attached database name or KNullDesC for the main database
       
   643 @param aPragmaSql Pragma sql statement
       
   644 @param aStmtHandle An output parameter where the statement handle will be stored
       
   645 
       
   646 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   647 @panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated
       
   648 
       
   649 @return KErrNone,     Operation completed successfully;
       
   650 		KErrNoMemory, Out of memory;
       
   651 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   652 
       
   653 @internalComponent
       
   654 */
       
   655 static TInt PreRetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, sqlite3_stmt*& aStmtHandle)
       
   656 	{
       
   657 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   658 	__SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument);
       
   659 	__SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument);
       
   660 	TBuf8<KMaxFileName> dbName;
       
   661 	if(!UTF16ToUTF8(aDbName, dbName))
       
   662 		{
       
   663 		return KErrGeneral;
       
   664 		}
       
   665 	TBuf8<KMaxFileName + 64> sql;//64 characters is enough for the longest PRAGMA statement
       
   666 	if(dbName == KNullDesC8)
       
   667 		{
       
   668 		sql.Format(aPragmaSql, &KMainDb8);
       
   669 		}
       
   670 	else
       
   671 		{
       
   672 		sql.Format(aPragmaSql, &dbName);
       
   673 		}
       
   674 	aStmtHandle = NULL;
       
   675 	TInt err = ::StmtPrepare8(aDbHandle, sql, aStmtHandle);
       
   676 	if(err == KErrNone)
       
   677 		{
       
   678 		__SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj);
       
   679 		err = ::StmtNext(aStmtHandle);
       
   680 		}
       
   681 	PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "PreRetrievePragmaValue()", sql);
       
   682 	return err;
       
   683 	}
       
   684 
       
   685 /**
       
   686 Prepares and executes PRAGMA statement and retrieves the value of column 0 (the pragma value).
       
   687 
       
   688 @param aDbHandle Database handle
       
   689 @param aDbName Attached database name or KNullDesC for the main database
       
   690 @param aPragmaSql Pragma sql statement
       
   691 @param aPragmaValue An output parameter where the pragma value will be stored
       
   692 
       
   693 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   694 @panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated
       
   695 
       
   696 @return KErrNone,     Operation completed successfully;
       
   697 		KErrNoMemory, Out of memory;
       
   698 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   699 
       
   700 @internalComponent
       
   701 */
       
   702 static TInt RetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, TInt& aPragmaValue)
       
   703 	{
       
   704 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   705 	__SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument);
       
   706 	__SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument);
       
   707 	sqlite3_stmt* stmtHandle = NULL;
       
   708 	TInt err = PreRetrievePragmaValue(aDbHandle, aDbName, aPragmaSql, stmtHandle);
       
   709 	if(err == KSqlAtRow)
       
   710 		{
       
   711 		aPragmaValue = sqlite3_column_int(stmtHandle, 0);
       
   712 		__SQLASSERT(aPragmaValue >= 0, ESqlPanicInternalError);
       
   713 		err = KErrNone;
       
   714 		}
       
   715 	TInt err2 = FinalizeStmtHandle(stmtHandle);
       
   716 	if(err == KErrNone && err2 != KErrNone)
       
   717 		{//FinalizeStmtHandle() has failed
       
   718 		err = err2;
       
   719 		}
       
   720 	return err;
       
   721 	}
       
   722 
       
   723 /**
       
   724 Prepares and executes PRAGMA statement and retrieves the value of column 0 (the pragma value) as text.
       
   725 
       
   726 @param aDbHandle Database handle
       
   727 @param aDbName Attached database name or KNullDesC for the main database
       
   728 @param aPragmaSql Pragma sql statement
       
   729 @param aPragmaValue An output parameter where the pragma value will be stored (as text)
       
   730 
       
   731 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   732 @panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated
       
   733 
       
   734 @return KErrNone,     Operation completed successfully;
       
   735 		KErrNoMemory, Out of memory;
       
   736 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   737 
       
   738 @internalComponent
       
   739 */
       
   740 static TInt RetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, TDes8& aPragmaValue)
       
   741 	{
       
   742 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   743 	__SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument);
       
   744 	__SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument);
       
   745 	sqlite3_stmt* stmtHandle = NULL;
       
   746 	TInt err = PreRetrievePragmaValue(aDbHandle, aDbName, aPragmaSql, stmtHandle);
       
   747 	if(err == KSqlAtRow)
       
   748 		{
       
   749 		TPtrC8 ptr(sqlite3_column_text(stmtHandle, 0));
       
   750 		aPragmaValue.Copy(ptr);
       
   751 		err = KErrNone;
       
   752 		}
       
   753 	TInt err2 = FinalizeStmtHandle(stmtHandle);
       
   754 	if(err == KErrNone && err2 != KErrNone)
       
   755 		{//::FinalizeStmtHandle() has failed
       
   756 		err = err2;
       
   757 		}
       
   758 	return err;
       
   759 	}
       
   760 
       
   761 /**
       
   762 Retrieves the database pages count.
       
   763 
       
   764 @param aDbHandle Database handle
       
   765 @param aDbName Attached database name or KNullDesC for the main database
       
   766 @param aPageCount An output parameter where the database pages count will be stored
       
   767 
       
   768 @return KErrNone,     Operation completed successfully;
       
   769 		KErrNoMemory, Out of memory;
       
   770 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   771 
       
   772 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   773 
       
   774 @internalComponent
       
   775 */
       
   776 TInt DbPageCount(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageCount)
       
   777 	{
       
   778 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   779 	return RetrievePragmaValue(aDbHandle, aDbName, KPageCountPragma, aPageCount);
       
   780 	}
       
   781 
       
   782 /**
       
   783 Retrieves the database page size.
       
   784 
       
   785 @param aDbHandle Database handle
       
   786 @param aDbName Attached database name or KNullDesC for the main database
       
   787 @param aPageSize An output parameter where the page size will be stored
       
   788 
       
   789 @return KErrNone,     Operation completed successfully;
       
   790 		KErrNoMemory, Out of memory;
       
   791 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   792 
       
   793 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   794 
       
   795 @internalComponent
       
   796 */
       
   797 TInt DbPageSize(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageSize)
       
   798 	{
       
   799 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   800 	return RetrievePragmaValue(aDbHandle, aDbName, KPageSizePragma, aPageSize);
       
   801 	}
       
   802 
       
   803 /**
       
   804 Retrieves the database cache size in pages.
       
   805 
       
   806 @param aDbHandle Database handle
       
   807 @param aDbName Attached database name or KNullDesC for the main database
       
   808 @param aCacheSize An output parameter where the cache size will be stored
       
   809 
       
   810 @return KErrNone,     Operation completed successfully;
       
   811 		KErrNoMemory, Out of memory;
       
   812 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   813 
       
   814 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   815 
       
   816 @internalComponent
       
   817 */
       
   818 TInt DbCacheSize(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aCacheSize)
       
   819 	{
       
   820 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   821 	return RetrievePragmaValue(aDbHandle, aDbName, KCacheSizePragma, aCacheSize);
       
   822 	}
       
   823 
       
   824 /**
       
   825 Retrieves the database encoding.
       
   826 
       
   827 @param aDbHandle Database handle
       
   828 @param aDbName Attached database name or KNullDesC for the main database
       
   829 @param aEncoding An output parameter where the encoding type will be stored (as text)
       
   830 
       
   831 @return KErrNone,     Operation completed successfully;
       
   832 		KErrNoMemory, Out of memory;
       
   833 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   834 
       
   835 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   836 
       
   837 @internalComponent
       
   838 */
       
   839 TInt DbEncoding(sqlite3* aDbHandle, const TDesC& aDbName, TDes8& aEncoding)
       
   840 	{
       
   841 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   842 	return RetrievePragmaValue(aDbHandle, aDbName, KEncodingPragma, aEncoding);
       
   843 	}
       
   844 
       
   845 /**
       
   846 Retrieves the database free pages count.
       
   847 
       
   848 @param aDbHandle Database handle
       
   849 @param aDbName Attached database name or KNullDesC for the main database
       
   850 @param aPageCount An output parameter where the free pages count will be stored
       
   851 
       
   852 @return KErrNone,     Operation completed successfully;
       
   853 		KErrNoMemory, Out of memory;
       
   854 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   855 
       
   856 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   857 
       
   858 @internalComponent
       
   859 */
       
   860 TInt DbFreePageCount(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageCount)
       
   861 	{
       
   862 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   863 	return RetrievePragmaValue(aDbHandle, aDbName, KFreePageCountPragma, aPageCount);
       
   864 	}
       
   865 
       
   866 /**
       
   867 Retrieves the current vacuum mode of the database.
       
   868 
       
   869 @param aDbHandle Database handle
       
   870 @param aDbName Attached database name or KNullDesC for the main database
       
   871 @param aVacuumMode An output parameter where the current vacuum mode will be stored
       
   872 
       
   873 @return KErrNone,     Operation completed successfully;
       
   874 		KErrNoMemory, Out of memory;
       
   875 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   876 
       
   877 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   878 
       
   879 @internalComponent
       
   880 */
       
   881 TInt DbVacuumMode(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aVacuumMode)
       
   882 	{
       
   883 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   884 	return RetrievePragmaValue(aDbHandle, aDbName, KVacuumModePragma, aVacuumMode);
       
   885 	}
       
   886 
       
   887 static TBool IsCompactTimeLimitReached(TUint32 aStartTicks, TUint32 aCurrTicks, TInt aMaxTime)
       
   888 	{
       
   889 	__SQLASSERT(aMaxTime > 0, ESqlPanicBadArgument);
       
   890 	TInt64 tickDiff64 = (TInt64)aCurrTicks - (TInt64)aStartTicks;
       
   891 	if(tickDiff64 < 0)
       
   892 		{
       
   893 		tickDiff64 = KMaxTUint32 + tickDiff64 + 1;
       
   894 		}
       
   895 	static TInt freq = 0;
       
   896 	TInt err = KErrNone;
       
   897 	if(freq == 0)
       
   898 		{
       
   899 		err = HAL::Get(HAL::EFastCounterFrequency, freq);
       
   900 		}
       
   901 	if(err == KErrNone && freq > 0)
       
   902 		{
       
   903 		const TInt KMicroSecIn1Sec = 1000000;
       
   904 		const TInt KMicroSecIn1Ms = 1000;
       
   905 		TInt64 usDiff64 = (tickDiff64 * KMicroSecIn1Sec) / freq;
       
   906 		if(usDiff64 > aMaxTime * KMicroSecIn1Ms)
       
   907 			{
       
   908 			return ETrue;	
       
   909 			}
       
   910 		}
       
   911 	return EFalse;
       
   912 	}
       
   913 
       
   914 /**
       
   915 Compacts the database.
       
   916 
       
   917 @param aDbHandle 			Database handle.
       
   918 @param aPageCount 			Count of the free database pages to be removed from the file.
       
   919 @param aProcessedPageCount	Output parameter. How many pages actually have been removed from the file.
       
   920 @param aMaxTime				The max allowed time in milliseconds for the compact operation.
       
   921 							If aMaxTime is zero, then aPageCount pages will be removed regardless the time.
       
   922 
       
   923 @return KErrNone,     Operation completed successfully;
       
   924 					  Other system-wide error codes or SQL errors of ESqlDbError type.
       
   925 
       
   926 @panic SqlDb 4 In _DEBUG mode if aPageCount is negative
       
   927 @panic SqlDb 4 In _DEBUG mode if aMaxTime is negative
       
   928 @panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
       
   929 
       
   930 @internalComponent
       
   931 */
       
   932 TInt DbCompact(sqlite3* aDbHandle, const TDesC& aDbName, TInt aPageCount, TInt& aProcessedPageCount, TInt aMaxTime)
       
   933 	{
       
   934 	__SQLASSERT(aPageCount >= 0, ESqlPanicBadArgument);
       
   935 	__SQLASSERT(aMaxTime >= 0, ESqlPanicBadArgument);
       
   936 	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
       
   937 	TBuf8<KMaxFileName> dbName;
       
   938 	if(!UTF16ToUTF8(aDbName, dbName))
       
   939 		{
       
   940 		return KErrGeneral;
       
   941 		}
       
   942 	TBuf8<KMaxFileName + sizeof(KIncrementalVacuumPragma) + 1> sql;
       
   943 	if(dbName == KNullDesC8)
       
   944 		{
       
   945 		sql.Format(KIncrementalVacuumPragma, &KMainDb8, aPageCount);
       
   946 		}
       
   947 	else
       
   948 		{
       
   949 		sql.Format(KIncrementalVacuumPragma, &dbName, aPageCount);
       
   950 		}
       
   951 	//Currently there is no way to check how many pages have been compacted without executing a "PRAGMA freelist_count"	
       
   952 	//statement, if sqlite3_exec() is used. 
       
   953 	//So, instead of calling sqlite3_exec(), the function prepares and executes the "PRAGMA incremental_vacuum(N)"
       
   954 	//statement using sqlite3_step() and counts the steps, because each step compacts one page.
       
   955 	(void)sqlite3SymbianLastOsError();//clear last OS error
       
   956 	sqlite3_stmt* stmtHandle = NULL;
       
   957 	const char* stmtTail = NULL;
       
   958 	aProcessedPageCount = 0;
       
   959 	//sqlite3_prepare16() expects parameter #3 to be one of the following:
       
   960 	// - byte length of the sql statement, excluding terminating zero;
       
   961 	// - negative value - zero-terminated sql statement;
       
   962 	TInt err = sqlite3_prepare_v2(aDbHandle, (const char*)sql.Ptr(), sql.Length() - sizeof(TUint8), &stmtHandle, &stmtTail);
       
   963 	__SQLASSERT(err == SQLITE_OK ? !stmtTail || User::StringLength((const TUint8*)stmtTail) == 0 : !stmtHandle, ESqlPanicInternalError);
       
   964 	if(stmtHandle)	//stmtHandle can be NULL for statements like this: ";".
       
   965 		{
       
   966 		if(err == SQLITE_OK)
       
   967 			{
       
   968 			TUint32 startTicks = 0;
       
   969 			if(aMaxTime > 0)
       
   970 				{
       
   971 				startTicks = User::FastCounter();
       
   972 				}
       
   973 			while((err = sqlite3_step(stmtHandle)) == SQLITE_ROW)
       
   974 				{
       
   975 				++aProcessedPageCount;
       
   976 				if(aMaxTime > 0 && IsCompactTimeLimitReached(startTicks, User::FastCounter(), aMaxTime))
       
   977 					{
       
   978 					err = SQLITE_DONE;//The statement execution did not complete because of the time limit
       
   979 					break;	
       
   980 					}
       
   981 				}
       
   982 			if(err == SQLITE_ERROR)	//It may be "out of memory" problem
       
   983 				{
       
   984 				err = sqlite3_reset(stmtHandle);
       
   985 				__SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError);
       
   986 				}
       
   987 			}
       
   988 		TInt err2 = sqlite3_finalize(stmtHandle);
       
   989 		if(err == SQLITE_DONE && err2 != SQLITE_OK)
       
   990 			{//use the "sqlite3_finalize" error
       
   991 			err = err2;				
       
   992 			}
       
   993 		}
       
   994 	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
   995 	if(err == KSqlAtEnd)
       
   996 		{
       
   997 		err = KErrNone;	
       
   998 		}
       
   999 	PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "DbCompact()", sql);
       
  1000 	return err;
       
  1001 	}
       
  1002 
       
  1003 /**
       
  1004 Finalizes the statement handle.
       
  1005 
       
  1006 @internalComponent
       
  1007 */
       
  1008 TInt FinalizeStmtHandle(sqlite3_stmt* aStmtHandle)
       
  1009 	{
       
  1010 	TInt err = KErrNone;
       
  1011 	if(aStmtHandle)
       
  1012 		{
       
  1013 		(void)sqlite3SymbianLastOsError();//clear last OS error
       
  1014 		err = sqlite3_finalize(aStmtHandle);
       
  1015 		err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
       
  1016 		}
       
  1017 	return err;
       
  1018 	}