persistentstorage/sql/SRC/Server/SqlSrvStatementUtil.cpp
changeset 0 08ec8eefde2f
child 9 667e88a979d7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/sql/SRC/Server/SqlSrvStatementUtil.cpp	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,1018 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <e32debug.h>
+#include <hal.h>
+#include <sqldb.h>
+#include "sqlite3.h"
+#include "SqlSrvStatementUtil.h"
+#include "SqlPanic.h"
+#include "SqlSrvUtil.h"
+#include "SqlUtil.h"
+#include "SqliteSymbian.h"		//sqlite3SymbianLastOsError()
+#include "SqlSrvResourceProfiler.h"
+
+//The database names in all statements are quoted to avoid the "sql injection" threat.
+_LIT8(KPageCountPragma, "PRAGMA \"%S\".page_count\x0");
+_LIT8(KPageSizePragma,  "PRAGMA \"%S\".page_size\x0");
+_LIT8(KCacheSizePragma,  "PRAGMA \"%S\".cache_size\x0");
+_LIT8(KEncodingPragma,  "PRAGMA \"%S\".encoding\x0");
+_LIT8(KFreePageCountPragma, "PRAGMA \"%S\".freelist_count\x0");
+_LIT8(KVacuumModePragma, "PRAGMA \"%S\".auto_vacuum\x0");
+_LIT8(KIncrementalVacuumPragma, "PRAGMA \"%S\".incremental_vacuum(%d)\x0");
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _NOTIFY
+static void PrintErrMsg8(TBool aCondition, sqlite3* aDbHandle, const char* aFuncNameZ, const TDesC8& aStmt)
+	{
+	if(!aCondition)
+		{
+		return;	
+		}
+	TPtrC8 funcName8(reinterpret_cast <const TUint8*> (aFuncNameZ));
+	TBuf<32> funcName;
+	funcName.Copy(funcName8);
+	RDebug::Print(_L("###%S\r\n"), &funcName);
+	TInt stmtLen = aStmt.Length();
+	if(stmtLen > 0)
+		{
+		if(aStmt[stmtLen - 1] == 0)
+			{
+			--stmtLen;
+			}
+		HBufC* buf = HBufC::New(stmtLen);
+		if(buf)
+			{
+			TPtr sqlStmt = buf->Des();
+			sqlStmt.Copy(aStmt.Left(stmtLen));
+			if(sqlStmt.Length() > 250)
+				{
+				sqlStmt.SetLength(250);		
+				}
+			RDebug::Print(_L("###\"%S\"\r\n"), &sqlStmt);
+			delete buf;
+			}
+		}
+	TBuf<16> tbuf;
+	Util::GetTimeStr(tbuf);
+	const void* errMsg = sqlite3_errmsg16(aDbHandle);//"errMsg" - zero terminated string
+	if(errMsg)
+		{
+		TPtrC msg(reinterpret_cast <const TText16*> (errMsg));//terminating zero character excluded.
+		if(msg.Length() > 230)
+			{
+			msg.Set(msg.Left(230));		
+			}
+		RDebug::Print(_L("##%S#ErrMsg=%S\r\n"), &tbuf, &msg);
+		}
+	else
+		{
+		RDebug::Print(_L("##%S#ErrMsg=null\r\n"), &tbuf);
+		}
+	}
+	
+static void PrintErrMsg16(TBool aCondition, sqlite3* aDbHandle, const char* aFuncNameZ, const TDesC16& aStmt)
+	{
+	if(!aCondition)
+		{
+		return;	
+		}
+	TPtrC8 funcName8(reinterpret_cast <const TUint8*> (aFuncNameZ));
+	TBuf<32> funcName;
+	funcName.Copy(funcName8);
+	RDebug::Print(_L("###%S\r\n"), &funcName);
+	TInt stmtLen = aStmt.Length();
+	if(stmtLen > 0)
+		{
+		if(aStmt[stmtLen - 1] == 0)
+			{
+			--stmtLen;
+			}
+		TPtrC sqlStmt(aStmt.Ptr(), stmtLen);
+		if(sqlStmt.Length() > 250)
+			{
+			sqlStmt.Set(sqlStmt.Left(250));		
+			}
+		RDebug::Print(_L("###\"%S\"\r\n"), &sqlStmt);
+		}
+	TBuf<16> tbuf;
+	Util::GetTimeStr(tbuf);
+	const void* errMsg = sqlite3_errmsg16(aDbHandle);//"errMsg" - zero terminated string
+	if(errMsg)
+		{
+		TPtrC msg(reinterpret_cast <const TText16*> (errMsg));//terminating zero character excluded.
+		if(msg.Length() > 230)
+			{
+			msg.Set(msg.Left(230));		
+			}
+		RDebug::Print(_L("##%S#ErrMsg=%S\r\n"), &tbuf, &msg);
+		}
+	else
+		{
+		RDebug::Print(_L("##%S#ErrMsg=null\r\n"), &tbuf);
+		}
+	}
+
+#define PRINT_ERRMSG8(Condition, DbHandle, FuncNameZ, Stmt) PrintErrMsg8(Condition, DbHandle, FuncNameZ, Stmt)
+#define PRINT_ERRMSG16(Condition, DbHandle, FuncNameZ, Stmt) PrintErrMsg16(Condition, DbHandle, FuncNameZ, Stmt)
+
+#else  //_NOTIFY
+
+#define PRINT_ERRMSG8(Condition, DbHandle, FuncNameZ, Stmt) 
+#define PRINT_ERRMSG16(Condition, DbHandle, FuncNameZ, Stmt) 
+	
+#endif //_NOTIFY
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//Calls sqlite3_open16() to create or open database file with aFileNameZ.
+//aFileNameZ is UTF16 encoded, zero-terminated.
+//The function returns system-wide errors or database specific errors.
+//The function may panic with code 7 in _DEBUG mode - internal error: the created database handle is NULL.
+TInt CreateDbHandle16(const TDesC& aFileNameZ, sqlite3*& aDbHandle)
+	{
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	TInt err = sqlite3_open16(aFileNameZ.Ptr(), &aDbHandle);
+	__SQLASSERT(err == SQLITE_OK ? aDbHandle != NULL : ETrue, ESqlPanicInternalError);
+	if(err == SQLITE_OK)
+		{
+		(void)sqlite3_extended_result_codes(aDbHandle, 0);
+		}
+	//Get the return error code now, because the next "if" may destroy it.
+	TInt rc = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+	if(err != SQLITE_OK)
+		{//Yes, it is possible error code != SQLITE_OK and aDbHandle != NULL.
+		CloseDbHandle(aDbHandle);
+		aDbHandle = NULL;
+		}
+	return rc;
+	}
+
+//Calls sqlite3_open() to create or open database file with aFileNameZ.
+//aFileNameZ is UTF8 encoded, zero-terminated.
+//The function returns system-wide errors or database specific errors.
+//The function may panic with code 7 in _DEBUG mode - internal error: the created database handle is NULL.
+TInt CreateDbHandle8(const TDesC8& aFileNameZ, sqlite3*& aDbHandle)
+	{
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	TInt err = sqlite3_open((const char *) aFileNameZ.Ptr(), &aDbHandle);
+	__SQLASSERT(err == SQLITE_OK ? aDbHandle != NULL : ETrue, ESqlPanicInternalError);
+	if(err == SQLITE_OK)
+		{
+		(void)sqlite3_extended_result_codes(aDbHandle, 0);
+		}
+	//Get the return error code now, because the next "if" may destroy it.
+	TInt rc = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+	if(err != SQLITE_OK)
+		{//Yes, it is possible error code != SQLITE_OK and aDbHandle != NULL.
+		CloseDbHandle(aDbHandle);
+		aDbHandle = NULL;
+		}
+	return rc;
+	}
+	
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////                     16-bit and 8-bit SQL statements execution upon completion                        ////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//16-bit SQL statement execution.
+//
+//aSql - zero-terminated string
+//
+//Prepares the supplied as an argument (aSql) 16-bit SQL statement and executes it.
+//If aSql argument contains more than one SQL statements, separated with ';', then
+//the function panics in _DEBUG mode (panic code 7).
+//
+//The function panics in debug mode (panic code 2) if aDbHandle is NULL.
+//
+//If the function completes successfully, it returns SQLITE_ROW or SQLITE_DONE.
+//If the function fails then it returns one of the SQLITE error codes.
+static TInt DoSingleStmtExec16(sqlite3 *aDbHandle, const TDesC16& aSql)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInvalidObj);
+	sqlite3_stmt* stmtHandle = NULL;
+	const void* stmtTail = NULL;
+	//sqlite3_prepare16_v2() expects parameter #3 to be one of the following:
+	// - byte length of the sql statement, excluding terminating zero;
+	// - negative value - zero-terminated sql statement;
+	TInt err = sqlite3_prepare16_v2(aDbHandle, aSql.Ptr(), aSql.Length() * sizeof(TUint16) - sizeof(TUint16), &stmtHandle, &stmtTail);
+	__SQLASSERT(err == SQLITE_OK ? !stmtTail || User::StringLength((const TUint16*)stmtTail) == 0 : !stmtHandle, ESqlPanicInternalError);
+	if(stmtHandle)	//stmtHandle can be NULL for statements like this: ";".
+		{
+		if(err == SQLITE_OK)
+			{
+			while((err = sqlite3_step(stmtHandle)) == SQLITE_ROW)
+				{
+				}
+			if(err == SQLITE_ERROR)	//It may be "out of memory" problem
+				{
+				err = sqlite3_reset(stmtHandle);
+				__SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError);
+				}
+			}
+		TInt err2 = sqlite3_finalize(stmtHandle);
+		if(err == SQLITE_DONE && err2 != SQLITE_OK)
+			{//return the "sqlite3_finalize" error
+			err = err2;	
+			}
+		}
+	return err;
+	}
+
+/**
+This function searches aString argument for ';' occurences.
+Every time when it finds a ';' character, the function places a zero character right after the ';' and
+tests the just created, zero-terminated substring if it is a comlpete SQL statement.
+
+If it is a SQL statement, the function replaces the found ';' character with zero and returns the just created
+zero-terminated substring.Also the function modifies aString argument to point right after the found
+SQL string. If it is not SQL statement, the function will continue the searching.
+
+If there is no ';' inside aString argument, the function returns the same string as a return result and
+modifies aString argument - sets it to TPtr(NULL, 0, 0).
+
+The function expects aString argument to be zero-terminated.
+
+@internalComponent
+*/
+TPtrC GetFirstSqlStmt(TPtr& aString)
+	{
+	const TChar KDelimitier(';');
+	TPtr originalStr(aString);
+	TPtr str(const_cast <TUint16*> (aString.Ptr()), aString.Length(), aString.Length());
+	TInt afterDelimitierPos = 0;
+	TInt pos;
+	while((pos = str.Locate(KDelimitier) + 1) > 0 && pos < str.Length())
+		{
+		//There is a possibility that the string, which terminates with the found ';' character, is a SQL statement.
+		//Zero terminate the string placing a zero right after the ';' character and test it using sqlite3_complete16().
+		//If it is not a SQL string, restore the original character and continue searching.
+		afterDelimitierPos += pos;
+		TChar ch = aString[afterDelimitierPos];
+		aString[afterDelimitierPos] = 0;
+		TInt res = sqlite3_complete16(aString.Ptr());
+		aString[afterDelimitierPos] = ch;
+		if(res)
+			{
+			str.Set(const_cast <TUint16*> (aString.Ptr()), afterDelimitierPos, afterDelimitierPos);	
+			//Replace the found ';' character with 0.
+			str[afterDelimitierPos - 1] = 0;
+			aString.Set(const_cast <TUint16*> (aString.Ptr()) + afterDelimitierPos, aString.Length() - afterDelimitierPos, aString.Length() - afterDelimitierPos);
+			return str;
+			}
+		str.Set(const_cast <TUint16*> (str.Ptr()) + pos, str.Length() - pos, str.Length() - pos);	
+		}
+	//aString argument does not contain valid SQL statement or there is no ';' character inside aString.
+	//Set aString to TPtr(NULL, 0, 0) and return the original string.
+	aString.Set(NULL, 0, 0);
+	str.Set(originalStr);
+	return str;
+	}
+
+/**
+Executes one or more 16-bit SQL statements. SQL statements of any kind can be executed, but the 
+method won't return any record(s) if the SQL statement type is "SELECT".
+If the SQL statement(s) contains one or more parameters, the method will execute it giving the parameters
+default NULL values.
+
+@param aDbHandle Database handle. Not NULL.
+@param aSqlStmt String containing one or more 16-bit SQL statements, separated with ';'. Zero-terminated string.
+				Note: The ExecL() call can modify the content of aSqlStmt argument.
+
+@return KErrNone, Operation completed successfully;
+		KErrNoMemory, Out of memory;
+		KSqlErrGeneral, Syntax error. A text message describing the problem can be obtained calling
+						RSqlDatabase::LastErrorMessage();
+						Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 4 In _DEBUG mode if aSqlStmt is not zero-terminated string
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbExecStmt16(sqlite3 *aDbHandle, TDes16& aSqlStmt)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	__SQLASSERT(aSqlStmt.Length() > 0 ? (TInt)aSqlStmt[aSqlStmt.Length() - 1] == 0: ETrue, ESqlPanicBadArgument);
+
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	
+	TInt err = SQLITE_DONE;
+	//Execute SQL statement(s)
+	//16-bit SQL string - no sqlite3_exec16() function, so the execution is made with 
+	//sqlite3_prepare16_v2() and sqlite3_step() functions.
+	TPtr16 sql(const_cast <TUint16*> (aSqlStmt.Ptr()), aSqlStmt.Length(), aSqlStmt.Length());
+	TPtrC firstSqlStmt(KNullDesC);
+	while(err == SQLITE_DONE && sql.Length() > 1) //"> 1" because it is a zero terminated string
+		{
+		firstSqlStmt.Set(GetFirstSqlStmt(sql));
+        SQLPROFILER_SQL16_PRINT((TUint)aDbHandle, firstSqlStmt.Left(firstSqlStmt.Length() - 1), EFalse);
+		err = ::DoSingleStmtExec16(aDbHandle, firstSqlStmt);
+		}
+		
+	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+	if(err == KSqlAtEnd)
+		{
+		err = KErrNone;	
+		}
+	PRINT_ERRMSG16(err <= KSqlErrGeneral, aDbHandle, "DbExecStmt16()", aSqlStmt);
+	return err;
+	}
+
+/**
+Executes one or more 8-bit SQL statements. SQL statements of any kind can be executed, but the 
+method won't return any record(s) if the SQL statement type is "SELECT".
+If the SQL statement(s) contains one or more parameters, the method will execute it giving the parameters
+default NULL values.
+
+@param aDbHandle Database handle. Not NULL.
+@param aSqlStmt String containing one or more 8-bit SQL statements, separated with ';'. Zero-terminated string.
+
+@return KErrNone, Operation completed successfully;
+		KErrNoMemory, Out of memory;
+		KSqlErrGeneral, Syntax error. A text message describing the problem can be obtained calling
+						RSqlDatabase::LastErrorMessage();
+		Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 4 In _DEBUG mode if aSqlStmt is not zero-terminated string
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbExecStmt8(sqlite3 *aDbHandle, const TDesC8& aSqlStmt)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	__SQLASSERT(aSqlStmt.Length() > 0 ? (TInt)aSqlStmt[aSqlStmt.Length() - 1] == 0: ETrue, ESqlPanicBadArgument);
+
+    SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), EFalse);
+	
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	
+	TInt err = sqlite3_exec(aDbHandle, reinterpret_cast <const char*> (aSqlStmt.Ptr()), NULL, NULL, NULL);
+
+	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+	if(err == KSqlAtEnd)
+		{
+		err = KErrNone;	
+		}
+	PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "DbExecStmt8()", aSqlStmt);
+	return err;
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////                     16-bit and 8-bit SQL statement preparation                                      /////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+//Prepares 16-bit SQL statement, returning in aStmtHandle the statement handle and
+//setting aHasTail to true, if aStmt contains more than one sql statements.
+//aStmt - zero-terminated string.
+//Returns one of SQLITE error codes.
+static TInt DoPrepareStmt16(sqlite3* aDbHandle, const TDesC& aStmt, sqlite3_stmt** aStmtHandle, TBool& aHasTail)
+	{
+	const void* stmtTail = NULL;
+	//sqlite3_prepare16_v2() expects parameter #3 to be one of the following:
+	// - byte length of the sql statement, excluding terminating zero;
+	// - negative value - zero-terminated sql statement;
+	TInt err = sqlite3_prepare16_v2(aDbHandle, aStmt.Ptr(), aStmt.Length() * sizeof(TUint16) - sizeof(TUint16), aStmtHandle, &stmtTail);
+	aHasTail = stmtTail && static_cast <const TUint16*> (stmtTail)[0] != 0;
+	PRINT_ERRMSG16(err != SQLITE_OK, aDbHandle, "DoPrepareStmt16()", aStmt);
+	__SQLASSERT(err != SQLITE_OK ? !(*aStmtHandle) : ETrue, ESqlPanicInternalError);
+	//(*aStmtHandle) is NULL for ";" statements, when err == SQLITE_OK. Since the server should not panic
+	//that situation is handled later (not inside the assert above)
+	return err;
+	}
+	
+//Prepares 8-bit SQL statement, returning in aStmtHandle the statement handle and
+//setting aHasTail to true, if aStmt contains more than one sql statements.
+//aStmt - zero-terminated string.
+//Returns one of SQLITE error codes.
+static TInt DoPrepareStmt8(sqlite3* aDbHandle, const TUint8* aStmt, sqlite3_stmt** aStmtHandle, TBool& aHasTail)
+	{
+	const char* stmtTail = NULL;
+	//sqlite3_prepare_v2() expects parameter #3 to be one of the following:
+	// - byte length of the sql statement;
+	// - negative value - zero-terminated sql statement;
+	TInt err = sqlite3_prepare_v2(aDbHandle, reinterpret_cast <const char*> (aStmt), -1, aStmtHandle, &stmtTail);
+	aHasTail = stmtTail && stmtTail[0] != 0;
+	PRINT_ERRMSG8(err != SQLITE_OK, aDbHandle, "DoPrepareStmt8()", TPtrC8(aStmt, aStmt ? User::StringLength(aStmt) : 0));
+	__SQLASSERT(err != SQLITE_OK ? !(*aStmtHandle) : ETrue, ESqlPanicInternalError);
+	//(*aStmtHandle) is NULL for ";" statements, when err == SQLITE_OK. Since the server should not panic
+	//that situation is handled later (not inside the assert above)
+	return err;
+	}
+
+//This function accepts as arguments the SQLITE error, the length of non-parsed part of the SQL statement
+//and the statement handle.
+//
+//It checks the arguments and returns an error if:
+// - aSqliteError != SQLITE_OK;
+// - aHasTail is true (possibly more than one SQL statement, separated with ";");
+// - aStmtHandle is NULL;
+//
+static TInt ProcessPrepareError(TInt aSqliteError, TBool aHasTail, sqlite3_stmt* aStmtHandle)
+	{
+	if(aSqliteError != SQLITE_OK)
+		{
+		return ::Sql2OsErrCode(aSqliteError, sqlite3SymbianLastOsError());
+		}
+	else if(aHasTail || !aStmtHandle)
+		{//More than one SQL statement or the SQL string is "" or ";;;" or ";   ;; ;". 
+		 //Report it as an error, because there is no statement handle.
+		return KErrArgument;
+		}
+	return KErrNone;
+	}
+
+//This function accepts as arguments the SQLITE error, the length of non-parsed part of the SQL statement
+//and the statement handle.
+//
+//It checks the arguments and leaves if:
+// - aSqliteError != SQLITE_OK;
+// - aHasTail is true (possibly more than one SQL statement, separated with ";");
+// - aStmtHandle is NULL;
+//
+static void LeaveIfPrepareErrorL(TInt aSqliteError, TBool aHasTail, sqlite3_stmt* aStmtHandle)
+	{
+	__SQLLEAVE_IF_ERROR(ProcessPrepareError(aSqliteError, aHasTail, aStmtHandle));
+	}
+
+/**
+Prepares 16-bit aSqlStmt SQL statement.
+
+@param aSqlStmt - zero-terminated string.
+
+@leave KErrNoMemory, if there is no memory;
+	   KErrArgument, if the SQL string contains more than one SQL statements;
+	   One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range.
+
+@return The prepared SQL statement handle.
+
+@internalComponent
+*/
+sqlite3_stmt* StmtPrepare16L(sqlite3* aDbHandle, const TDesC16& aSqlStmt)
+	{
+    SQLPROFILER_SQL16_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue);
+	
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	TBool hasTail = EFalse;
+	sqlite3_stmt* stmtHandle = NULL;
+	TInt err = DoPrepareStmt16(aDbHandle, aSqlStmt, &stmtHandle, hasTail);
+	LeaveIfPrepareErrorL(err, hasTail, stmtHandle);
+	return stmtHandle;
+	}
+
+/**
+Prepares 8-bit aSqlStmt SQL statement.
+
+@param aSqlStmt - zero-terminated string.
+
+@leave KErrNoMemory, if there is no memory;
+	   KErrArgument, if the SQL string contains more than one SQL statements;
+	   One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range.
+
+@return The prepared SQL statement handle.
+
+@internalComponent
+*/
+TInt StmtPrepare8(sqlite3* aDbHandle, const TDesC8& aSqlStmt, sqlite3_stmt*& aStmtHandle)
+	{
+    SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue);
+	
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	TBool hasTail = EFalse;
+	TInt err = DoPrepareStmt8(aDbHandle, aSqlStmt.Ptr(), &aStmtHandle, hasTail);
+	return ProcessPrepareError(err, hasTail, aStmtHandle);
+	}
+
+/**
+Prepares 8-bit aSqlStmt SQL statement.
+
+@param aSqlStmt - zero-terminated string.
+
+@leave KErrNoMemory, if there is no memory;
+	   KErrArgument, if the SQL string contains more than one SQL statements;
+	   One of the error codes in [KSqlErrGeneral..KSqlErrNotDb] range.
+
+@return The prepared SQL statement handle.
+
+@internalComponent
+*/
+sqlite3_stmt* StmtPrepare8L(sqlite3* aDbHandle, const TDesC8& aSqlStmt)
+	{
+    SQLPROFILER_SQL8_PRINT((TUint)aDbHandle, aSqlStmt.Left(aSqlStmt.Length() - 1), ETrue);
+	
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	TBool hasTail = EFalse;
+	sqlite3_stmt* stmtHandle = NULL;
+	TInt err = DoPrepareStmt8(aDbHandle, aSqlStmt.Ptr(), &stmtHandle, hasTail);
+	LeaveIfPrepareErrorL(err, hasTail, stmtHandle);
+	return stmtHandle;
+	}
+
+/**
+Executes upon completion the prepared SQL statement.
+
+@param aStmtHandle Prepared statement handle
+
+@return KSqlErrStmtExpired, Statement expired (if new functions or collating sequences are 
+							registered or if an authorizer function is added or changed);
+		KErrNoMemory, Out of memory. The statement will be reset;
+		KErrNone, The reset operation completed successfully.							
+
+@panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle.
+@panic SqlDb 7 In _DEBUG mode. SQLITE internal error. (SQLITE_ERROR, followed by a sqlite3_reset(), which returns SQLITE_OK)
+
+@internalComponent
+*/	
+TInt StmtExec(sqlite3_stmt* aStmtHandle)
+	{
+	__SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj);
+	
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	
+	if(sqlite3_expired(aStmtHandle))
+		{
+		return KSqlErrStmtExpired;
+		}
+		
+	TInt err;
+	while((err = sqlite3_step(aStmtHandle)) == SQLITE_ROW)
+		{
+		}
+		
+	if(err == SQLITE_ERROR)	//It may be "out of memory" problem
+		{
+		err = sqlite3_reset(aStmtHandle);
+		__SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError);
+		}
+		
+	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+	if(err == KSqlAtEnd)
+		{
+		err = KErrNone;	
+		}
+
+	PRINT_ERRMSG16(err <= KSqlErrGeneral, sqlite3_db_handle(aStmtHandle), "StmtExec()", _L(" "));
+	return err;
+	}
+
+/**
+Executes the SQL statement moving it to the next row if available.
+
+@return KSqlErrStmtExpired Statement expired (if new functions or collating sequences are 
+							registered or if an authorizer function is added or changed)
+@return KSqlAtRow, The next record data is ready for processing by the caller;
+		KSqlAtEnd, No more record data;
+		KSqlErrBusy, Database file is locked;
+		KSqlErrGeneral, Run-time error. Next() should not be called anymore;
+		KSqlErrMisuse, Next() called after KSqlAtEnd or KSqlErrGeneral returned by the previous Next() call;
+		KErrNoMemory, Out of memory. The statement will be reset.
+
+@panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle.
+@panic SqlDb 7 In _DEBUG mode. SQLITE internal error. (SQLITE_ERROR, followed by a sqlite3_reset(), which returns SQLITE_OK)
+
+@internalComponent
+*/	
+TInt StmtNext(sqlite3_stmt* aStmtHandle)
+	{
+	__SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj);
+	
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	
+	if(sqlite3_expired(aStmtHandle))
+		{
+		return KSqlErrStmtExpired;
+		}
+		
+	TInt err = sqlite3_step(aStmtHandle);
+	if(err == SQLITE_ERROR)	//It may be "out of memory" problem
+		{
+		err = sqlite3_reset(aStmtHandle);
+		__SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError);
+		}
+	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+	PRINT_ERRMSG16(err <= KSqlErrGeneral, sqlite3_db_handle(aStmtHandle), "StmtNext()", _L(" "));
+	return err;
+	}
+
+/**
+Resets the prepared SQL statement to its initial state and makes it ready to be executed again.
+Any SQL statement parameters that had values bound to them, retain their values.
+
+@return KSqlErrStmtExpired, Statement expired (if new functions or collating sequences are 
+							registered or if an authorizer function is added or changed);
+		KErrNone, The reset operation completed successfully.							
+
+@panic SqlDb 2 In _DEBUG mode. Invalid (NULL) statement handle.
+
+@internalComponent
+*/	
+TInt StmtReset(sqlite3_stmt* aStmtHandle)
+	{
+	__SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj);
+	
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	
+	if(sqlite3_expired(aStmtHandle))
+		{
+		return KSqlErrStmtExpired;
+		}
+		
+	TInt err = sqlite3_reset(aStmtHandle);
+	return ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+	}
+
+/**
+Prepares and executes PRAGMA statement and moves the statement cursor on the first row.
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aPragmaSql Pragma sql statement
+@param aStmtHandle An output parameter where the statement handle will be stored
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+@panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@internalComponent
+*/
+static TInt PreRetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, sqlite3_stmt*& aStmtHandle)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	__SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument);
+	__SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument);
+	TBuf8<KMaxFileName> dbName;
+	if(!UTF16ToUTF8(aDbName, dbName))
+		{
+		return KErrGeneral;
+		}
+	TBuf8<KMaxFileName + 64> sql;//64 characters is enough for the longest PRAGMA statement
+	if(dbName == KNullDesC8)
+		{
+		sql.Format(aPragmaSql, &KMainDb8);
+		}
+	else
+		{
+		sql.Format(aPragmaSql, &dbName);
+		}
+	aStmtHandle = NULL;
+	TInt err = ::StmtPrepare8(aDbHandle, sql, aStmtHandle);
+	if(err == KErrNone)
+		{
+		__SQLASSERT(aStmtHandle != NULL, ESqlPanicInvalidObj);
+		err = ::StmtNext(aStmtHandle);
+		}
+	PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "PreRetrievePragmaValue()", sql);
+	return err;
+	}
+
+/**
+Prepares and executes PRAGMA statement and retrieves the value of column 0 (the pragma value).
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aPragmaSql Pragma sql statement
+@param aPragmaValue An output parameter where the pragma value will be stored
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+@panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@internalComponent
+*/
+static TInt RetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, TInt& aPragmaValue)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	__SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument);
+	__SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument);
+	sqlite3_stmt* stmtHandle = NULL;
+	TInt err = PreRetrievePragmaValue(aDbHandle, aDbName, aPragmaSql, stmtHandle);
+	if(err == KSqlAtRow)
+		{
+		aPragmaValue = sqlite3_column_int(stmtHandle, 0);
+		__SQLASSERT(aPragmaValue >= 0, ESqlPanicInternalError);
+		err = KErrNone;
+		}
+	TInt err2 = FinalizeStmtHandle(stmtHandle);
+	if(err == KErrNone && err2 != KErrNone)
+		{//FinalizeStmtHandle() has failed
+		err = err2;
+		}
+	return err;
+	}
+
+/**
+Prepares and executes PRAGMA statement and retrieves the value of column 0 (the pragma value) as text.
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aPragmaSql Pragma sql statement
+@param aPragmaValue An output parameter where the pragma value will be stored (as text)
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+@panic SqlDb 4 In _DEBUG mode if aPragmaSql length is 0 or if the statement is not zero-terminated
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@internalComponent
+*/
+static TInt RetrievePragmaValue(sqlite3* aDbHandle, const TDesC& aDbName, const TDesC8& aPragmaSql, TDes8& aPragmaValue)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	__SQLASSERT(aPragmaSql.Length() > 0, ESqlPanicBadArgument);
+	__SQLASSERT(aPragmaSql[aPragmaSql.Length() - 1] == 0, ESqlPanicBadArgument);
+	sqlite3_stmt* stmtHandle = NULL;
+	TInt err = PreRetrievePragmaValue(aDbHandle, aDbName, aPragmaSql, stmtHandle);
+	if(err == KSqlAtRow)
+		{
+		TPtrC8 ptr(sqlite3_column_text(stmtHandle, 0));
+		aPragmaValue.Copy(ptr);
+		err = KErrNone;
+		}
+	TInt err2 = FinalizeStmtHandle(stmtHandle);
+	if(err == KErrNone && err2 != KErrNone)
+		{//::FinalizeStmtHandle() has failed
+		err = err2;
+		}
+	return err;
+	}
+
+/**
+Retrieves the database pages count.
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aPageCount An output parameter where the database pages count will be stored
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbPageCount(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageCount)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	return RetrievePragmaValue(aDbHandle, aDbName, KPageCountPragma, aPageCount);
+	}
+
+/**
+Retrieves the database page size.
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aPageSize An output parameter where the page size will be stored
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbPageSize(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageSize)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	return RetrievePragmaValue(aDbHandle, aDbName, KPageSizePragma, aPageSize);
+	}
+
+/**
+Retrieves the database cache size in pages.
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aCacheSize An output parameter where the cache size will be stored
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbCacheSize(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aCacheSize)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	return RetrievePragmaValue(aDbHandle, aDbName, KCacheSizePragma, aCacheSize);
+	}
+
+/**
+Retrieves the database encoding.
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aEncoding An output parameter where the encoding type will be stored (as text)
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbEncoding(sqlite3* aDbHandle, const TDesC& aDbName, TDes8& aEncoding)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	return RetrievePragmaValue(aDbHandle, aDbName, KEncodingPragma, aEncoding);
+	}
+
+/**
+Retrieves the database free pages count.
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aPageCount An output parameter where the free pages count will be stored
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbFreePageCount(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aPageCount)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	return RetrievePragmaValue(aDbHandle, aDbName, KFreePageCountPragma, aPageCount);
+	}
+
+/**
+Retrieves the current vacuum mode of the database.
+
+@param aDbHandle Database handle
+@param aDbName Attached database name or KNullDesC for the main database
+@param aVacuumMode An output parameter where the current vacuum mode will be stored
+
+@return KErrNone,     Operation completed successfully;
+		KErrNoMemory, Out of memory;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbVacuumMode(sqlite3* aDbHandle, const TDesC& aDbName, TInt& aVacuumMode)
+	{
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	return RetrievePragmaValue(aDbHandle, aDbName, KVacuumModePragma, aVacuumMode);
+	}
+
+static TBool IsCompactTimeLimitReached(TUint32 aStartTicks, TUint32 aCurrTicks, TInt aMaxTime)
+	{
+	__SQLASSERT(aMaxTime > 0, ESqlPanicBadArgument);
+	TInt64 tickDiff64 = (TInt64)aCurrTicks - (TInt64)aStartTicks;
+	if(tickDiff64 < 0)
+		{
+		tickDiff64 = KMaxTUint32 + tickDiff64 + 1;
+		}
+	static TInt freq = 0;
+	TInt err = KErrNone;
+	if(freq == 0)
+		{
+		err = HAL::Get(HAL::EFastCounterFrequency, freq);
+		}
+	if(err == KErrNone && freq > 0)
+		{
+		const TInt KMicroSecIn1Sec = 1000000;
+		const TInt KMicroSecIn1Ms = 1000;
+		TInt64 usDiff64 = (tickDiff64 * KMicroSecIn1Sec) / freq;
+		if(usDiff64 > aMaxTime * KMicroSecIn1Ms)
+			{
+			return ETrue;	
+			}
+		}
+	return EFalse;
+	}
+
+/**
+Compacts the database.
+
+@param aDbHandle 			Database handle.
+@param aPageCount 			Count of the free database pages to be removed from the file.
+@param aProcessedPageCount	Output parameter. How many pages actually have been removed from the file.
+@param aMaxTime				The max allowed time in milliseconds for the compact operation.
+							If aMaxTime is zero, then aPageCount pages will be removed regardless the time.
+
+@return KErrNone,     Operation completed successfully;
+					  Other system-wide error codes or SQL errors of ESqlDbError type.
+
+@panic SqlDb 4 In _DEBUG mode if aPageCount is negative
+@panic SqlDb 4 In _DEBUG mode if aMaxTime is negative
+@panic SqlDb 7 In _DEBUG mode if aDbHandle is NULL
+
+@internalComponent
+*/
+TInt DbCompact(sqlite3* aDbHandle, const TDesC& aDbName, TInt aPageCount, TInt& aProcessedPageCount, TInt aMaxTime)
+	{
+	__SQLASSERT(aPageCount >= 0, ESqlPanicBadArgument);
+	__SQLASSERT(aMaxTime >= 0, ESqlPanicBadArgument);
+	__SQLASSERT(aDbHandle != NULL, ESqlPanicInternalError);
+	TBuf8<KMaxFileName> dbName;
+	if(!UTF16ToUTF8(aDbName, dbName))
+		{
+		return KErrGeneral;
+		}
+	TBuf8<KMaxFileName + sizeof(KIncrementalVacuumPragma) + 1> sql;
+	if(dbName == KNullDesC8)
+		{
+		sql.Format(KIncrementalVacuumPragma, &KMainDb8, aPageCount);
+		}
+	else
+		{
+		sql.Format(KIncrementalVacuumPragma, &dbName, aPageCount);
+		}
+	//Currently there is no way to check how many pages have been compacted without executing a "PRAGMA freelist_count"	
+	//statement, if sqlite3_exec() is used. 
+	//So, instead of calling sqlite3_exec(), the function prepares and executes the "PRAGMA incremental_vacuum(N)"
+	//statement using sqlite3_step() and counts the steps, because each step compacts one page.
+	(void)sqlite3SymbianLastOsError();//clear last OS error
+	sqlite3_stmt* stmtHandle = NULL;
+	const char* stmtTail = NULL;
+	aProcessedPageCount = 0;
+	//sqlite3_prepare16() expects parameter #3 to be one of the following:
+	// - byte length of the sql statement, excluding terminating zero;
+	// - negative value - zero-terminated sql statement;
+	TInt err = sqlite3_prepare_v2(aDbHandle, (const char*)sql.Ptr(), sql.Length() - sizeof(TUint8), &stmtHandle, &stmtTail);
+	__SQLASSERT(err == SQLITE_OK ? !stmtTail || User::StringLength((const TUint8*)stmtTail) == 0 : !stmtHandle, ESqlPanicInternalError);
+	if(stmtHandle)	//stmtHandle can be NULL for statements like this: ";".
+		{
+		if(err == SQLITE_OK)
+			{
+			TUint32 startTicks = 0;
+			if(aMaxTime > 0)
+				{
+				startTicks = User::FastCounter();
+				}
+			while((err = sqlite3_step(stmtHandle)) == SQLITE_ROW)
+				{
+				++aProcessedPageCount;
+				if(aMaxTime > 0 && IsCompactTimeLimitReached(startTicks, User::FastCounter(), aMaxTime))
+					{
+					err = SQLITE_DONE;//The statement execution did not complete because of the time limit
+					break;	
+					}
+				}
+			if(err == SQLITE_ERROR)	//It may be "out of memory" problem
+				{
+				err = sqlite3_reset(stmtHandle);
+				__SQLASSERT(err != SQLITE_OK, ESqlPanicInternalError);
+				}
+			}
+		TInt err2 = sqlite3_finalize(stmtHandle);
+		if(err == SQLITE_DONE && err2 != SQLITE_OK)
+			{//use the "sqlite3_finalize" error
+			err = err2;				
+			}
+		}
+	err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+	if(err == KSqlAtEnd)
+		{
+		err = KErrNone;	
+		}
+	PRINT_ERRMSG8(err <= KSqlErrGeneral, aDbHandle, "DbCompact()", sql);
+	return err;
+	}
+
+/**
+Finalizes the statement handle.
+
+@internalComponent
+*/
+TInt FinalizeStmtHandle(sqlite3_stmt* aStmtHandle)
+	{
+	TInt err = KErrNone;
+	if(aStmtHandle)
+		{
+		(void)sqlite3SymbianLastOsError();//clear last OS error
+		err = sqlite3_finalize(aStmtHandle);
+		err = ::Sql2OsErrCode(err, sqlite3SymbianLastOsError());
+		}
+	return err;
+	}