// Copyright (c) 2008-2010 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 <e32std.h>
#include <e32debug.h>
#include <f32file.h>
#include "SqlPanic.h"
#include "SqlSrvResourceProfiler.h"
#include "SqlResourceProfiler.h"
#include "SqliteSymbian.h"
#include <hal.h>

#ifdef _SQLPROFILER

///////////////////////////////// Heap max alloc /////////////////////////////////////

/**
If true the max alloc profiling is enabled.
@internalComponent
*/
TBool TheSqlSrvProfilerMaxAllocEnabled = EFalse;
/**
The size of the biggest memory block ever allocated by the SQL server.
Set only if compiled with _SQLPROFILER macro.
@internalComponent
*/
TInt  TheSqlSrvProfilerMaxAllocSize = 0;

////////////////////////// IPC & SQL tracing related //////////////////////////////////

/**
If true the tracing is enabled (IPC calls & SQL statements).
@internalComponent
*/
static TBool TheSqlSrvProfilerTraceEnabled = EFalse;
/**
Trace level:
 - 0: no IPC calls traced (default);
 - 1: only the 10 most important IPC calls traced - SQL statement execution, ....
 - 2: all IPC calls traced; 
@internalComponent
*/
static TInt TheSqlSrvProfilerTraceLevel = 0;
/**
If true the SQL statement tracing is enabled.
@internalComponent
*/
static TBool TheSqlSrvProfilerSqlTraceEnabled = EFalse;

/**
When KSqlSrvProfilerDbName is with non-zero length, then only traces coming from database identified by
KSqlSrvProfilerDbName name are printed out. 
@internalComponent
*/
//_LIT(KSqlSrvProfilerDbName, "default_avacon.dbSQL");
_LIT(KSqlSrvProfilerDbName, "");
static TUint TheSqlSrvProfilerHandle = 0;

//File "read", "write", "sync" and "set size" counters, incremented inside the OS porting layer.
TInt TheSqlSrvProfilerFileRead = 0;
TInt TheSqlSrvProfilerFileWrite = 0;
TInt TheSqlSrvProfilerFileSync = 0;
TInt TheSqlSrvProfilerFileSetSize = 0;

//Set it to true if you want traces to be stored into a file.
static TBool TheSqlSrvProfilerTraceToFile = EFalse;

//"Prepared" and "Executed" SQL statement counters
static TInt TheSqlSrvProfilerPreparedCnt8 = 0;
static TInt TheSqlSrvProfilerPreparedCnt16 = 0;
static TInt TheSqlSrvProfilerExecutedCnt8 = 0;
static TInt TheSqlSrvProfilerExecutedCnt16 = 0;

///////////////////////////////// IPC counters ///////////////////////////////////////

/**
If true the IPC profiling is enabled.
@internalComponent
*/
TBool TheSqlSrvProfilerIpcEnabled = EFalse;
/**
IPC requests, read and write counters.
@internalComponent
*/
TInt  TheSqlSrvProfilerIpc[ESqlIpcLast] = {0};
/**
IPC read and write - bytes.
@internalComponent
*/
TInt64 TheSqlSrvProfilerIpcBytes[ESqlIpcLast] = {0};

//////////////////////////////////////////////////////////////////////////////////////

/**
Starts the specified profiling counter.

@leave KErrNotSupported, The requested profiling type is not supported;
                 		 The function may also leave with some other system-wide error codes.

Usage of the IPC call arguments:
 - Arg 0: [in]  profiling counter type, one of the TSqlResourceProfiler::TSqlCounter enum item values.
 - Arg 1: [in]  the length of the additional profiling parameters.
 - Arg 2: [in]  additional profiling parameters.
*/
void TSqlSrvResourceProfiler::StartL(const RMessage2& aMessage)
	{
	const TSqlResourceProfiler::TSqlCounter KCounterType = static_cast <TSqlResourceProfiler::TSqlCounter> (aMessage.Int0());
	TInt err = KErrNone;
	switch(KCounterType)
		{
		case TSqlResourceProfiler::ESqlCounterFileIO:
		case TSqlResourceProfiler::ESqlCounterOsCall:
		case TSqlResourceProfiler::ESqlCounterOsCallTime:
		case TSqlResourceProfiler::ESqlCounterOsCallDetails:
			err = sqlite3SymbianProfilerStart(KCounterType);
			break;
		case TSqlResourceProfiler::ESqlCounterIpc:
			TheSqlSrvProfilerIpcEnabled = ETrue;
			break;
		case TSqlResourceProfiler::ESqlCounterMemory:
			err = sqlite3SymbianProfilerStart(KCounterType);
			break;
		case TSqlResourceProfiler::ESqlCounterMaxAlloc:
			TheSqlSrvProfilerMaxAllocEnabled = ETrue;
			err = sqlite3SymbianProfilerStart(KCounterType);
			break;
		case TSqlResourceProfiler::ESqlCounterTrace:
		    {
			TheSqlSrvProfilerTraceEnabled = ETrue;
		    TInt len = aMessage.Int1();
		    __SQLPANIC_CLIENT((TUint)len < 64, aMessage, ESqlPanicBadArgument);
		    if(len > 0)
		        {
                TBuf8<64> prmBuf;
                aMessage.ReadL(2, prmBuf);
                prmBuf.UpperCase();
                TPtrC8 ptr(prmBuf);
                _LIT8(KLevel0, "L0");
                _LIT8(KLevel1, "L1");
                _LIT8(KLevel2, "L2");
                _LIT8(KSqlStmtTraceOff, "S0");
                _LIT8(KSqlStmtTraceOn, "S1");
                while(ptr.Length() > 0)
                    {
                    TInt pos = ptr.Locate(TChar(';'));
                    TPtrC8 str = ptr;
                    if(pos >= 0)
                        {
                        str.Set(ptr.Left(pos));
                        }
                    if(str == KLevel0)
                        {
                        TheSqlSrvProfilerTraceLevel = 0;
                        }
                    else if(str == KLevel1)
                        {
                        TheSqlSrvProfilerTraceLevel = 1;
                        }
                    else if(str == KLevel2)
                        {
                        TheSqlSrvProfilerTraceLevel = 2;
                        }
                    else if(str == KSqlStmtTraceOff)
                        {
                        TheSqlSrvProfilerSqlTraceEnabled = EFalse;
                        }
                    else if(str == KSqlStmtTraceOn)
                        {
                        TheSqlSrvProfilerSqlTraceEnabled = ETrue;
                        }
                    if((TUint)pos > (ptr.Length() - 1))
                        {
                        break;
                        }
                    ptr.Set(ptr.Mid(pos + 1));
                    }
		        }
		    }
			break;
		default:
			err = KErrNotSupported;
			break;
		}
	__SQLLEAVE_IF_ERROR(err);
	}
	
/**
Stops the specified profiling counter.

@leave KErrNotSupported, The requested profiling type is not supported;
                 		 The function may also leave with some other system-wide error codes.

Usage of the IPC call arguments:
 - Arg 0: [in]  profiling counter type, one of the TSqlResourceProfiler::TSqlCounter enum item values.
*/
void TSqlSrvResourceProfiler::StopL(const RMessage2& aMessage)
	{
	const TSqlResourceProfiler::TSqlCounter KCounterType = static_cast <TSqlResourceProfiler::TSqlCounter> (aMessage.Int0());
	TInt err = KErrNone;
	switch(KCounterType)
		{
		case TSqlResourceProfiler::ESqlCounterFileIO:
		case TSqlResourceProfiler::ESqlCounterOsCall:
		case TSqlResourceProfiler::ESqlCounterOsCallTime:
		case TSqlResourceProfiler::ESqlCounterOsCallDetails:
			err = sqlite3SymbianProfilerStop(KCounterType);
			break;
		case TSqlResourceProfiler::ESqlCounterIpc:
			TheSqlSrvProfilerIpcEnabled = EFalse;
			break;
		case TSqlResourceProfiler::ESqlCounterMemory:
			err = sqlite3SymbianProfilerStop(KCounterType);
			break;
		case TSqlResourceProfiler::ESqlCounterMaxAlloc:
			TheSqlSrvProfilerMaxAllocEnabled = EFalse;
			err = sqlite3SymbianProfilerStop(KCounterType);
			break;
        case TSqlResourceProfiler::ESqlCounterTrace:
            TheSqlSrvProfilerTraceEnabled = EFalse;
            TheSqlSrvProfilerSqlTraceEnabled = EFalse;
            TheSqlSrvProfilerTraceLevel = 0;
            TheSqlSrvProfilerHandle = 0;
            break;
		default:
			err = KErrNotSupported;
			break;
		}
	__SQLLEAVE_IF_ERROR(err);
	}
	
/**
Resets the specified profiling counter.

@leave KErrNotSupported, The requested profiling type is not supported;
                 		 The function may also leave with some other system-wide error codes.

Usage of the IPC call arguments:
 - Arg 0: [in]  profiling counter type, one of the TSqlResourceProfiler::TSqlCounter enum item values.
*/
void TSqlSrvResourceProfiler::ResetL(const RMessage2& aMessage)
	{
	const TSqlResourceProfiler::TSqlCounter KCounterType = static_cast <TSqlResourceProfiler::TSqlCounter> (aMessage.Int0());
	TInt err = KErrNone;
	switch(KCounterType)
		{
		case TSqlResourceProfiler::ESqlCounterFileIO:
		case TSqlResourceProfiler::ESqlCounterOsCall:
		case TSqlResourceProfiler::ESqlCounterOsCallTime:
		case TSqlResourceProfiler::ESqlCounterOsCallDetails:
			err = sqlite3SymbianProfilerReset(KCounterType);
			break;
		case TSqlResourceProfiler::ESqlCounterIpc:
			Mem::FillZ(TheSqlSrvProfilerIpc, sizeof(TheSqlSrvProfilerIpc));
			Mem::FillZ(TheSqlSrvProfilerIpcBytes, sizeof(TheSqlSrvProfilerIpcBytes));
			break;
		case TSqlResourceProfiler::ESqlCounterMemory:
			err = sqlite3SymbianProfilerReset(KCounterType);
			break;
		case TSqlResourceProfiler::ESqlCounterMaxAlloc:
			TheSqlSrvProfilerMaxAllocSize = 0;
			err = sqlite3SymbianProfilerReset(KCounterType);
			break;
        case TSqlResourceProfiler::ESqlCounterTrace:
            break;
		default:
			err = KErrNotSupported;
			break;
		}
	__SQLLEAVE_IF_ERROR(err);
	}
	
/**
Retrieves the counter values for the specified profiling counter.

@leave KErrNotSupported, The requested profiling type is not supported;
                 		 The function may also leave with some other system-wide error codes.

@see TSqlResourceProfiler

Usage of the IPC call arguments:
 - Arg 0: [in]  profiling counter type, one of the TSqlResourceProfiler::TSqlCounter enum item values.
 - Arg 1: [in]  the size of the buffer for the profiling counter values.
 - Arg 2: [out] the buffer for the profiling counter values.
*/
void TSqlSrvResourceProfiler::QueryL(const RMessage2& aMessage)
	{
	const TSqlResourceProfiler::TSqlCounter KCounterType = static_cast <TSqlResourceProfiler::TSqlCounter> (aMessage.Int0());
	const TInt KIpcBufLen = 300;
	TBuf8<KIpcBufLen> ipcBuf;
	TInt err = KErrNone;
	switch(KCounterType)
		{
		case TSqlResourceProfiler::ESqlCounterFileIO:
		case TSqlResourceProfiler::ESqlCounterOsCall:
		case TSqlResourceProfiler::ESqlCounterOsCallTime:
		case TSqlResourceProfiler::ESqlCounterOsCallDetails:
			err = sqlite3SymbianProfilerQuery(KCounterType, ipcBuf);
			break;
		case TSqlResourceProfiler::ESqlCounterIpc:
			ipcBuf.AppendNum(TheSqlSrvProfilerIpc[ESqlIpcRq]);
			ipcBuf.Append(TChar(';'));
			ipcBuf.AppendNum(TheSqlSrvProfilerIpc[ESqlIpcRead]);
			ipcBuf.Append(TChar(';'));
			ipcBuf.AppendNum(TheSqlSrvProfilerIpc[ESqlIpcWrite]);
			ipcBuf.Append(TChar(';'));
			ipcBuf.AppendNum(TheSqlSrvProfilerIpcBytes[ESqlIpcRead]);
			ipcBuf.Append(TChar(';'));
			ipcBuf.AppendNum(TheSqlSrvProfilerIpcBytes[ESqlIpcWrite]);
			ipcBuf.Append(TChar(';'));
			break;
		case TSqlResourceProfiler::ESqlCounterMemory:
			{
			TInt totalAllocCells = 0;
			TInt totalAllocSize = 0;
			TInt totalFreeSpace = 0;
			TInt biggestBlockSize = 0;
			RHeap& heap = User::Heap();;
			totalAllocCells = heap.AllocSize(totalAllocSize);
			totalFreeSpace = heap.Available(biggestBlockSize);
			ipcBuf.AppendNum(totalAllocCells);
			ipcBuf.Append(TChar(';'));
			ipcBuf.AppendNum(totalAllocSize);
			ipcBuf.Append(TChar(';'));
			ipcBuf.AppendNum(totalFreeSpace);
			ipcBuf.Append(TChar(';'));
			ipcBuf.AppendNum(biggestBlockSize);
			ipcBuf.Append(TChar(';'));
			err = sqlite3SymbianProfilerQuery(KCounterType, ipcBuf);
			}
			break;
		case TSqlResourceProfiler::ESqlCounterMaxAlloc:
			ipcBuf.AppendNum(TheSqlSrvProfilerMaxAllocSize);
			ipcBuf.Append(TChar(';'));
			err = sqlite3SymbianProfilerQuery(KCounterType, ipcBuf);
			break;
        case TSqlResourceProfiler::ESqlCounterTrace:
            break;
		default:
			err = KErrNotSupported;
			break;
		}
	__SQLLEAVE_IF_ERROR(err);
	aMessage.WriteL(2, ipcBuf);
	}
	
////////////////////////// IPC tracing related ////////////////////////////////////////

//Max trace line length
const TInt KSqlTraceMaxLength = 220;
//Trace buffer.
static TBuf<KSqlTraceMaxLength> TheSqlTraceBuf;

//IPC calls names - begin
_LIT(KSqlSrvDbCreate, "DbCreate");
_LIT(KSqlSrvDbCreateSecure, "DbCreateSecure");
_LIT(KSqlSrvDbOpen, "DbOpen");
_LIT(KSqlSrvDbOpenFromHandle, "DbOpenFromHandle");
_LIT(KSqlSrvDbClose, "DbClose");
_LIT(KSqlSrvDbCopy, "DbCopy");
_LIT(KSqlSrvDbDelete, "DbDelete");
_LIT(KSqlSrvLastErrorMsg, "LastErrorMsg");
_LIT(KSqlSrvDbExec8, "DbExec8");
_LIT(KSqlSrvDbExec16, "DbExec16");
_LIT(KSqlSrvDbSetIsolationLevel, "DbSetIsolationLevel");
_LIT(KSqlSrvDbGetSecurityPolicy, "DbGetSecurityPolicy");
_LIT(KSqlSrvDbAttach, "DbAttach");
_LIT(KSqlSrvDbAttachFromHandle, "DbAttachFromHandle");
_LIT(KSqlSrvDbDetach, "DbDetach");
_LIT(KSqlSrvDbScalarFullSelect8, "DbScalarFullSelect8");
_LIT(KSqlSrvDbScalarFullSelect16, "DbScalarFullSelect16");
_LIT(KSqlSrvDbInTransaction, "DbInTransaction");
_LIT(KSqlSrvDbSize, "DbSize");
_LIT(KSqlSrvDbSize2, "DbSize2");
_LIT(KSqlSrvDbBlobSource, "DbBlobSource");
_LIT(KSqlSrvDbLastInsertedRowId, "DbLastInsertedRowId");
_LIT(KSqlSrvDbCompact, "DbCompact");
_LIT(KSqlSrvDbReserveDriveSpace, "DbReserveDriveSpace");
_LIT(KSqlSrvDbFreeReservedSpace, "DbFreeReservedSpace");
_LIT(KSqlSrvDbGetReserveAccess, "DbGetReserveAccess");
_LIT(KSqlSrvDbReleaseReserveAccess, "DbReleaseReserveAccess");
_LIT(KSqlSrvStmtPrepare8, "StmtPrepare8");
_LIT(KSqlSrvStmtPrepare16, "StmtPrepare16");
_LIT(KSqlSrvStmtClose, "StmtClose");
_LIT(KSqlSrvStmtReset, "StmtReset");
_LIT(KSqlSrvStmtExec, "StmtExec");
_LIT(KSqlSrvStmtAsyncExec, "StmtAsyncExec");
_LIT(KSqlSrvStmtBindExec, "StmtBindExec");
_LIT(KSqlSrvStmtAsyncBindExec, "StmtAsyncBindExec");
_LIT(KSqlSrvStmtNext, "StmtNext");
_LIT(KSqlSrvStmtBindNext, "StmtBindNext");
_LIT(KSqlSrvStmtColumnNames, "StmtColumnNames");
_LIT(KSqlSrvStmtParamNames, "StmtParamNames");
_LIT(KSqlSrvStmtColumnSource, "StmtColumnSource");
_LIT(KSqlSrvStmtBinParamSink, "StmtBinParamSink");
_LIT(KSqlSrvStmtTxtParamSink16, "StmtTxtParamSink16");
_LIT(KSqlSrvStmtBufFlat, "StmtBufFlat");
_LIT(KSqlSrvStmtColumnValue, "StmtColumnValue");
_LIT(KSqlSrvStmtDeclColumnTypes, "StmtDeclColumnTypes");
_LIT(KSqlSrvStreamRead, "StreamRead");
_LIT(KSqlSrvStreamWrite, "StreamWrite");
_LIT(KSqlSrvStreamSize, "StreamSize");
_LIT(KSqlSrvStreamSynch, "StreamSynch");
_LIT(KSqlSrvStreamClose, "StreamClose");
//IPC calls names - end

//Gets as an argument the IPC call type in "aCode" parameter.
//Returns: 
// 0 or positive integer: the IPC call is one of the 10 most important IPC calls (trace level 0).
// KErrNotFound         : the IPC call is some of the other possible call types (trace level 1).
// KErrNotSupported     : unknown IPC call type.
//
// aIpcCallName will always be set to IPC call name descriptor.
static TInt SqlIpcTraceIdxAndName(TSqlSrvFunction aCode, TPtrC& aIpcCallName)
    {
    TInt rc = KErrNotFound;
    switch(aCode)
        {
        case ESqlSrvDbCreate:
            aIpcCallName.Set(KSqlSrvDbCreate);
            break;
        case ESqlSrvDbCreateSecure:
            aIpcCallName.Set(KSqlSrvDbCreateSecure);
            break;
        case ESqlSrvDbOpen:
            aIpcCallName.Set(KSqlSrvDbOpen);
            break;
        case ESqlSrvDbOpenFromHandle:
            aIpcCallName.Set(KSqlSrvDbOpenFromHandle);
            break;
        case ESqlSrvDbClose:
            aIpcCallName.Set(KSqlSrvDbClose);
            break;
        case ESqlSrvDbCopy:
            aIpcCallName.Set(KSqlSrvDbCopy);
            break;
        case ESqlSrvDbDelete:
            aIpcCallName.Set(KSqlSrvDbDelete);
            break;
        case ESqlSrvLastErrorMsg:
            aIpcCallName.Set(KSqlSrvLastErrorMsg);
            break;
        case ESqlSrvDbExec8:
            aIpcCallName.Set(KSqlSrvDbExec8);
            rc = 0;
            break;
        case ESqlSrvDbExec16:
            aIpcCallName.Set(KSqlSrvDbExec16);
            rc = 1;
            break;
        case ESqlSrvDbSetIsolationLevel:
            aIpcCallName.Set(KSqlSrvDbSetIsolationLevel);
            break;
        case ESqlSrvDbGetSecurityPolicy:
            aIpcCallName.Set(KSqlSrvDbGetSecurityPolicy);
            break;
        case ESqlSrvDbAttach:
            aIpcCallName.Set(KSqlSrvDbAttach);
            break;
        case ESqlSrvDbAttachFromHandle:
            aIpcCallName.Set(KSqlSrvDbAttachFromHandle);
            break;
        case ESqlSrvDbDetach:
            aIpcCallName.Set(KSqlSrvDbDetach);
            break;
        case ESqlSrvDbScalarFullSelect8:
            aIpcCallName.Set(KSqlSrvDbScalarFullSelect8);
            rc = 2;
            break;
        case ESqlSrvDbScalarFullSelect16:
            aIpcCallName.Set(KSqlSrvDbScalarFullSelect16);
            rc = 3;
            break;
        case ESqlSrvDbInTransaction:
            aIpcCallName.Set(KSqlSrvDbInTransaction);
            break;
        case ESqlSrvDbSize:
            aIpcCallName.Set(KSqlSrvDbSize);
            break;
        case ESqlSrvDbSize2:
            aIpcCallName.Set(KSqlSrvDbSize2);
            break;
        case ESqlSrvDbBlobSource:
            aIpcCallName.Set(KSqlSrvDbBlobSource);
            break;
        case ESqlSrvDbLastInsertedRowId:
            aIpcCallName.Set(KSqlSrvDbLastInsertedRowId);
            break;
        case ESqlSrvDbCompact:
            aIpcCallName.Set(KSqlSrvDbCompact);
            break;
        case ESqlSrvDbReserveDriveSpace:
            aIpcCallName.Set(KSqlSrvDbReserveDriveSpace);
            break;
        case ESqlSrvDbFreeReservedSpace:
            aIpcCallName.Set(KSqlSrvDbFreeReservedSpace);
            break;
        case ESqlSrvDbGetReserveAccess:
            aIpcCallName.Set(KSqlSrvDbGetReserveAccess);
            break;
        case ESqlSrvDbReleaseReserveAccess:
            aIpcCallName.Set(KSqlSrvDbReleaseReserveAccess);
            break;
        case ESqlSrvStmtPrepare8:
            aIpcCallName.Set(KSqlSrvStmtPrepare8);
            break;
        case ESqlSrvStmtPrepare16:
            aIpcCallName.Set(KSqlSrvStmtPrepare16);
            break;
        case ESqlSrvStmtClose:
            aIpcCallName.Set(KSqlSrvStmtClose);
            break;
        case ESqlSrvStmtReset:
            aIpcCallName.Set(KSqlSrvStmtReset);
            break;
        case ESqlSrvStmtExec:
            aIpcCallName.Set(KSqlSrvStmtExec);
            rc = 4;
            break;
        case ESqlSrvStmtAsyncExec:
            aIpcCallName.Set(KSqlSrvStmtAsyncExec);
            rc = 5;
            break;
        case ESqlSrvStmtBindExec:
            aIpcCallName.Set(KSqlSrvStmtBindExec);
            rc = 6;
            break;
        case ESqlSrvStmtAsyncBindExec:
            aIpcCallName.Set(KSqlSrvStmtAsyncBindExec);
            rc = 7;
            break;
        case ESqlSrvStmtNext:
            aIpcCallName.Set(KSqlSrvStmtNext);
            rc = 8;
            break;
        case ESqlSrvStmtBindNext:
            aIpcCallName.Set(KSqlSrvStmtBindNext);
            rc = 9;
            break;
        case ESqlSrvStmtColumnNames:
            aIpcCallName.Set(KSqlSrvStmtColumnNames);
            break;
        case ESqlSrvStmtParamNames:
            aIpcCallName.Set(KSqlSrvStmtParamNames);
            break;
        case ESqlSrvStmtColumnSource:
            aIpcCallName.Set(KSqlSrvStmtColumnSource);
            break;
        case ESqlSrvStmtBinParamSink:
            aIpcCallName.Set(KSqlSrvStmtBinParamSink);
            break;
        case ESqlSrvStmtTxtParamSink16:
            aIpcCallName.Set(KSqlSrvStmtTxtParamSink16);
            break;
        case ESqlSrvStmtBufFlat:
            aIpcCallName.Set(KSqlSrvStmtBufFlat);
            break;
        case ESqlSrvStmtColumnValue:
            aIpcCallName.Set(KSqlSrvStmtColumnValue);
            break;
        case ESqlSrvStmtDeclColumnTypes:
            aIpcCallName.Set(KSqlSrvStmtDeclColumnTypes);
            break;
        case ESqlSrvStreamRead:
            aIpcCallName.Set(KSqlSrvStreamRead);
            break;
        case ESqlSrvStreamWrite:
            aIpcCallName.Set(KSqlSrvStreamWrite);
            break;
        case ESqlSrvStreamSize:
            aIpcCallName.Set(KSqlSrvStreamSize);
            break;
        case ESqlSrvStreamSynch:
            aIpcCallName.Set(KSqlSrvStreamSynch);
            break;
        case ESqlSrvStreamClose:
            aIpcCallName.Set(KSqlSrvStreamClose);
            break;
        default:
            return KErrNotSupported;
        };
    __SQLASSERT((TUint)rc < KIpcTraceTypeCount || rc == KErrNotFound, ESqlPanicInternalError);
    return rc;
    }

//Calculates and returns the time difference between aStartTicks and aEndTicks in microseconds.  
static TInt SqlConvertTicks2Us(TUint32 aStartTicks, TUint32 aEndTicks)
    {
    static TInt freq = 0;
    if(freq == 0)
        {
        TInt err = HAL::Get(HAL::EFastCounterFrequency, freq);
        if(err != KErrNone)
            {
            SqlPanic((TSqlPanic)err);
            }
        }
    TInt64 diffTicks = (TInt64)aEndTicks - (TInt64)aStartTicks;
    if(diffTicks < 0)
        {
        diffTicks = KMaxTUint32 + diffTicks + 1;
        }
    const TInt KMicroSecIn1Sec = 1000000;
    TInt32 us = (diffTicks * KMicroSecIn1Sec) / freq;
    return us;
    }

//Calculates the time since the first time this function has been called.
static TInt64 SqlTimeFromStartUs()
    {
    struct TStartTime
        {
        inline TStartTime()
            {
            iTime.UniversalTime();
            }
        TTime iTime;
        };
    static TStartTime startTime;
    TTime time;
    time.UniversalTime();
    TTimeIntervalMicroSeconds us = time.MicroSecondsFrom(startTime.iTime);
    const TInt64 KMaxDiff = 999999999999LL;//999999999999 is the max number that can be printed out using %12ld format spec
    if(us.Int64() < 0 || us.Int64() >= KMaxDiff)
        {
        startTime.iTime = time;
        us = 0;
        }
    return us.Int64();
    }


//Tracing data buffer
const TInt KSqlSrvProfilePrnBufSize = 300;
static TBuf<KSqlSrvProfilePrnBufSize> TheSqlSrvProfileTraceBuf;
static TBuf8<KSqlSrvProfilePrnBufSize> TheSqlSrvProfileTraceBuf8;

static RFs TheSqlSrvTraceFs;
static RFile TheTheSqlSrvTraceFile;
_LIT(KSqlSrvTraceFileName, "C:\\SQLTRACE");

//Prints out a time stamp
static void SqlSrvProfileTimePrintf()
    {
    static TInt64 prevTimeDiff = 0;;
    TInt64 timeDiff = SqlTimeFromStartUs();
    const TInt64 KTimeInterval = 1000000; 
    if((timeDiff - prevTimeDiff) >= KTimeInterval || timeDiff < prevTimeDiff)
        {
        prevTimeDiff = timeDiff;
        TTime time;
        time.UniversalTime();
        TDateTime dt = time.DateTime();
        TheSqlSrvProfileTraceBuf8.Format(_L8("[SQL]¬\"%X\"¬¬TME¬¬¬¬¬¬¬¬¬¬¬¬%02d:%02d:%02d:%06d¬Prep8¬%d¬Prep16¬%d¬Ex8¬%d¬Ex16¬%d"),
                timeDiff, dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond(),
                TheSqlSrvProfilerPreparedCnt8, TheSqlSrvProfilerPreparedCnt16, 
                TheSqlSrvProfilerExecutedCnt8, TheSqlSrvProfilerExecutedCnt16);
        if(TheSqlSrvProfilerTraceToFile)
            {
            TheSqlSrvProfileTraceBuf8.Append(_L8("\r\n"));
            (void)TheTheSqlSrvTraceFile.Write(TheSqlSrvProfileTraceBuf8);
            }
        else
            {
            TheSqlSrvProfileTraceBuf8.Append(_L8("\n"));
            RDebug::RawPrint(TheSqlSrvProfileTraceBuf8);
            }
        }
    }

//Trace types
enum TSqlSrvProfilerTraceType
    {
    ESqlSrvProfilerNonSqlTrace,
    ESqlSrvProfilerMiddleLineSqlTrace,
    ESqlSrvProfilerLastLineSqlTrace
    };

//Prints out the data that is in TheSqlSrvProfileTraceBuf.
// aType = ESqlSrvProfilerNonSqlTrace       - non-SQL trace
// aType = ESqlSrvProfilerMiddleLineSqlTrace - not last line of an SQL trace
// aType = ESqlSrvProfilerLastLineSqlTrace  - last line of an SQL trace
static void SqlSrvProfilePrintf(TSqlSrvProfilerTraceType aType)
    {
    SqlSrvProfileTimePrintf();
    TheSqlSrvProfileTraceBuf8.Copy(TheSqlSrvProfileTraceBuf);
    if(TheSqlSrvProfilerTraceToFile)
        {
        if(aType == 0 || aType == 2)
            {
            TheSqlSrvProfileTraceBuf8.Append(_L8("\r\n"));
            }
        (void)TheTheSqlSrvTraceFile.Write(TheSqlSrvProfileTraceBuf8);
        }
    else
        {
        TheSqlSrvProfileTraceBuf8.Append(_L8("\n"));
        RDebug::RawPrint(TheSqlSrvProfileTraceBuf8);
        }
    }

//Called at the beginning of CSqlSrvSession::ServiceL().
void SqlIpcStart(TUint& aIpcCounter, TUint32& aStartTicks, TUint aDbHandle)
    {
    if(TheSqlSrvProfilerTraceEnabled)
        {
        TheSqlSrvProfilerFileRead = TheSqlSrvProfilerFileWrite = TheSqlSrvProfilerFileSync = TheSqlSrvProfilerFileSetSize = 0;
        if(TheSqlSrvProfilerTraceLevel == 0)
            {
            return;
            }
        if(KSqlSrvProfilerDbName().Length() > 0 && (aDbHandle == 0 || TheSqlSrvProfilerHandle != aDbHandle))
            {
            return;
            }
        ++aIpcCounter;
        aStartTicks = User::FastCounter();
        }
    }

//Called at the end of CSqlSrvSession::ServiceL().
void SqlIpcEnd(TUint aIpcCounter, TUint32 aStartTicks, TSqlSrvFunction aFuncCode, 
               TUint aDbHandle, TSqlSrvIpcTraceData aIpcTraceData[], TInt aRetCode)
    {
    if(TheSqlSrvProfilerTraceEnabled)
        {
        if(TheSqlSrvProfilerTraceLevel == 0)
            {
            return;
            }
        if(KSqlSrvProfilerDbName().Length() > 0 &&  (aDbHandle == 0 || TheSqlSrvProfilerHandle != aDbHandle))
            {
            return;
            }
        TUint32 endTicks = User::FastCounter();
        TInt executionTime = SqlConvertTicks2Us(aStartTicks, endTicks);
        TPtrC ipcCallName;
        TInt ipcCallIdx = SqlIpcTraceIdxAndName(aFuncCode, ipcCallName); 
        TInt64 timeFromStart = SqlTimeFromStartUs();
        TInt64 ttlExecTime = 0;
        TInt count = 0;
        if(ipcCallIdx >= 0)
            {
            aIpcTraceData[ipcCallIdx].iExecutionTime += executionTime;
            ttlExecTime = aIpcTraceData[ipcCallIdx].iExecutionTime;
            count = ++aIpcTraceData[ipcCallIdx].iCount;
            }
        if(ipcCallIdx >= 0  || (ipcCallIdx == KErrNotFound && TheSqlSrvProfilerTraceLevel == 2))
            {
            TheSqlSrvProfileTraceBuf.Format(_L("[SQL]¬\"%X\"¬%ld¬IPC¬%u¬%S¬%ld¬%d¬%d¬%d¬%d¬%d¬%d¬rc¬%d"),  
														//[SQL]
                    aDbHandle,							//Database handle
                    timeFromStart,						//Time from start, microseconds
														//IPC
                    aIpcCounter,						//IPC sequence counter for this database (connection)
                    &ipcCallName,						//IPC call name
                    ttlExecTime,						//All time spent in this IPC call type for this database (connection)
                    executionTime,						//This IPC call execution time
                    count,								//This IPC call sequence counter for this database (connection)
                    TheSqlSrvProfilerFileRead,			//File read count, performed during this IPC
                    TheSqlSrvProfilerFileWrite,			//File write count, performed during this IPC
                    TheSqlSrvProfilerFileSync,			//File flush count, performed during this IPC
                    TheSqlSrvProfilerFileSetSize,		//File set size count, performed during this IPC
                    aRetCode);							//IPC call - return code
            SqlSrvProfilePrintf(ESqlSrvProfilerNonSqlTrace);
            }
        }
    }

//Called at the end of CSqlSrvSession::ServiceError().
void SqlIpcError(TUint aIpcCounter, TSqlSrvFunction aFuncCode, TUint aDbHandle, TInt aError)
    {
    if(TheSqlSrvProfilerTraceEnabled)
        {
        if(KSqlSrvProfilerDbName().Length() > 0 &&  (aDbHandle == 0 || TheSqlSrvProfilerHandle != aDbHandle))
            {
            return;
            }
        TPtrC ipcCallName;
        (void)SqlIpcTraceIdxAndName(aFuncCode, ipcCallName); 
        TInt64 timeFromStart = SqlTimeFromStartUs();
        TheSqlSrvProfileTraceBuf.Format(_L("[SQL]¬\"%X\"¬%ld¬ERR¬%u¬%S¬¬¬¬¬¬¬¬err¬%d"), 
									//[SQL]
                aDbHandle,			//Database (connection) handle
                timeFromStart,		//Time from start, microseconds
									//ERR
                aIpcCounter,		//IPC sequence counter for this database (connection)
                &ipcCallName,		//IPC call name
                aError);			//IPC call - return code
        SqlSrvProfilePrintf(ESqlSrvProfilerNonSqlTrace);
        }
    }

//Prints the passed as a parameter 16-bit SQL statement.
void SqlPrintSql16(TUint aDbHandle, const TDesC& aSql, TBool aPrepare)
    {
    if(!TheSqlSrvProfilerTraceEnabled || !TheSqlSrvProfilerSqlTraceEnabled)
        {
        return;
        }
    if(KSqlSrvProfilerDbName().Length() > 0 &&  (aDbHandle == 0 || TheSqlSrvProfilerHandle != aDbHandle))
        {
        return;
        }
    
    aPrepare ? ++TheSqlSrvProfilerPreparedCnt16 : ++TheSqlSrvProfilerExecutedCnt16;
    
    TInt64 timeFromStart = SqlTimeFromStartUs();
    TPtr line((TUint16*)TheSqlTraceBuf.Ptr(), 0, TheSqlTraceBuf.MaxLength());
    TInt len = aSql.Length();
    TInt pos = 0;
    do
        {
        _LIT(KPrepare,  "Prepare16");
        _LIT(KExec,     "Exec16");
        _LIT(KEmptyStr,  "");
        if(pos == 0)
            {
            line.Format(_L("[SQL]¬\"%X\"¬%ld¬SQL¬¬%S¬¬¬¬¬¬¬¬¬¬"), aDbHandle, timeFromStart, aPrepare ? &KPrepare : &KExec);
            }
        else
            {
            if(!TheSqlSrvProfilerTraceToFile)
                {
                line.Format(_L("[SQL]¬\"%X\"¬%ld¬SQL¬¬%S¬¬¬¬¬¬¬¬¬¬"), aDbHandle, timeFromStart, &KEmptyStr);
                }
            }
        TInt l = Min(len, (line.MaxLength() - line.Length()));
        TPtrC ptr(aSql.Ptr() + pos, l);
        pos += l;
        len -= l;
        line.Append(ptr);
        TheSqlSrvProfileTraceBuf.Format(_L("%S"), &line); 
        SqlSrvProfilePrintf(len > 0 ? ESqlSrvProfilerMiddleLineSqlTrace : ESqlSrvProfilerLastLineSqlTrace);
        line.Zero();
        } while(len > 0);
    }
 
//Prints the passed as a parameter 8-bit SQL statement.
void SqlPrintSql8(TUint aDbHandle, const TDesC8& aSql, TBool aPrepare)
    {
    if(!TheSqlSrvProfilerTraceEnabled || !TheSqlSrvProfilerSqlTraceEnabled)
        {
        return;
        }
    if(KSqlSrvProfilerDbName().Length() > 0 &&  (aDbHandle == 0 || TheSqlSrvProfilerHandle != aDbHandle))
        {
        return;
        }
    
    aPrepare ? ++TheSqlSrvProfilerPreparedCnt8 : ++TheSqlSrvProfilerExecutedCnt8;
    
    TInt64 timeFromStart = SqlTimeFromStartUs();
    TPtr line((TUint16*)TheSqlTraceBuf.Ptr(), 0, TheSqlTraceBuf.MaxLength());
    TInt len = aSql.Length();
    TInt pos = 0;
    do
        {
        _LIT(KPrepare,   "Prepare8");
        _LIT(KExec,      "Exec8");
        _LIT(KEmptyStr,  "");
        if(pos == 0)
            {
            line.Format(_L("[SQL]¬\"%X\"¬%ld¬SQL¬¬%S¬¬¬¬¬¬¬¬¬¬"), aDbHandle, timeFromStart, aPrepare ? &KPrepare : &KExec);
            }
        else
            {
            if(!TheSqlSrvProfilerTraceToFile)
                {
                line.Format(_L("[SQL]¬\"%X\"¬%ld¬SQL¬¬%S¬¬¬¬¬¬¬¬¬¬"), aDbHandle, timeFromStart, &KEmptyStr);
                }
            }
        TInt l = Min(len, (line.MaxLength() - line.Length()));
        TPtrC8 ptr(aSql.Ptr() + pos, l);
        pos += l;
        len -= l;
        TPtr p2((TUint16*)line.Ptr() + line.Length(), 0, l);  
        p2.Copy(ptr);
        line.SetLength(line.Length() + p2.Length());
        TheSqlSrvProfileTraceBuf.Format(_L("%S"), &line); 
        SqlSrvProfilePrintf(len > 0 ? ESqlSrvProfilerMiddleLineSqlTrace : ESqlSrvProfilerLastLineSqlTrace);
        line.Zero();
        } while(len > 0);
    }

//Prints the name of the just created database.
void SqlPrintDbCreate(TUint aDbHandle, const TDesC& aDbName)
    {
    if(TheSqlSrvProfilerTraceEnabled)
        {
        if(KSqlSrvProfilerDbName().Length() > 0 && aDbName.FindF(KSqlSrvProfilerDbName) >= 0)
            {
            TheSqlSrvProfilerHandle = aDbHandle;
            }
        if(KSqlSrvProfilerDbName().Length() > 0 &&  (aDbHandle == 0 || TheSqlSrvProfilerHandle != aDbHandle))
            {
            return;
            }
        TInt64 timeFromStart = SqlTimeFromStartUs();
        TheSqlSrvProfileTraceBuf.Format(_L("[SQL]¬\"%X\"¬%ld¬CRE¬¬¬¬¬¬¬¬¬¬¬¬%S"), 
                aDbHandle, 
                timeFromStart,
                &aDbName);
        SqlSrvProfilePrintf(ESqlSrvProfilerNonSqlTrace);
        }
    }

//Prints the name of the just opened database.
void SqlPrintDbOpen(TUint aDbHandle, const TDesC& aDbName)
    {
    if(TheSqlSrvProfilerTraceEnabled)
        {
        if(KSqlSrvProfilerDbName().Length() > 0 && aDbName.FindF(KSqlSrvProfilerDbName) >= 0)
            {
            TheSqlSrvProfilerHandle = aDbHandle;
            }
        if(KSqlSrvProfilerDbName().Length() > 0 &&  (aDbHandle == 0 || TheSqlSrvProfilerHandle != aDbHandle))
            {
            return;
            }
        TInt64 timeFromStart = SqlTimeFromStartUs();
        TheSqlSrvProfileTraceBuf.Format(_L("[SQL]¬\"%X\"¬%ld¬OPN¬¬¬¬¬¬¬¬¬¬¬¬%S"), 
                aDbHandle, 
                timeFromStart,
                &aDbName);
        SqlSrvProfilePrintf(ESqlSrvProfilerNonSqlTrace);
        }
    }

//Prints the handle of the just closed database.
void SqlPrintDbClose(TUint aDbHandle)
    {
    if(TheSqlSrvProfilerTraceEnabled)
        {
        if(KSqlSrvProfilerDbName().Length() > 0 &&  (aDbHandle == 0 || TheSqlSrvProfilerHandle != aDbHandle))
            {
            return;
            }
        TInt64 timeFromStart = SqlTimeFromStartUs();
        TheSqlSrvProfileTraceBuf.Format(_L("[SQL]¬\"%X\"¬%ld¬CSE"),  
                aDbHandle, 
                timeFromStart);
        SqlSrvProfilePrintf(ESqlSrvProfilerNonSqlTrace);
        if(aDbHandle == TheSqlSrvProfilerHandle)
            {
            TheSqlSrvProfilerHandle = 0;
            }
        }
    }

//Prints a trace when the SQL server starts
void SqlPrintServerStart()
    {
    TInt64 timeFromStart = SqlTimeFromStartUs();
    if(TheSqlSrvProfilerTraceToFile)
        {
        TInt err = TheSqlSrvTraceFs.Connect();
        if(err == KErrNone)
            {
            TInt fileNum = 0;
            err = KErrGeneral;
            while(++fileNum < 1000 && err != KErrNone)
                {
                TBuf<80> ftrname;
                ftrname.Copy(KSqlSrvTraceFileName);
                ftrname.AppendNum(fileNum);
                ftrname.Append(_L(".txt"));
                err = TheTheSqlSrvTraceFile.Create(TheSqlSrvTraceFs, ftrname, EFileRead | EFileWrite);
                if(err == KErrNone)
                    {
                    break;
                    }
                }
            }
        if(err != KErrNone)
            {
            TheSqlSrvTraceFs.Close();
            TheSqlSrvProfilerTraceToFile = EFalse;
            RDebug::Print(_L("SQL trace file creation failed with err=%d"), err);
            }
        }
    TheSqlSrvProfileTraceBuf.Format(_L("[SQL]¬¬%ld¬SRV¬¬Start"), timeFromStart); 
    SqlSrvProfilePrintf(ESqlSrvProfilerNonSqlTrace);
    }

//Prints a trace when the SQL server stops
void SqlPrintServerStop()
    {
    TInt64 timeFromStart = SqlTimeFromStartUs();
    TheSqlSrvProfileTraceBuf.Format(_L("[SQL]¬¬%ld¬SRV¬¬Stop"), timeFromStart); 
    SqlSrvProfilePrintf(ESqlSrvProfilerNonSqlTrace);
    if(TheSqlSrvProfilerTraceToFile)
        {
        TheTheSqlSrvTraceFile.Close();
        TheSqlSrvTraceFs.Close();
        }
    }

#else //_SQLPROFILER

void TSqlSrvResourceProfiler::StartL(const RMessage2&)
	{
	__SQLLEAVE(KErrNotSupported);
	}
	
void TSqlSrvResourceProfiler::StopL(const RMessage2&)
	{
	__SQLLEAVE(KErrNotSupported);
	}
	
void TSqlSrvResourceProfiler::ResetL(const RMessage2&)
	{
	__SQLLEAVE(KErrNotSupported);
	}
	
void TSqlSrvResourceProfiler::QueryL(const RMessage2&)
	{
	__SQLLEAVE(KErrNotSupported);
	}
	
#endif//_SQLPROFILER
