// Copyright (c) 2005-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:
// NTT DOCOMO, INC - Fix for Bug 1915 "SQL server panics when using long column type strings"
//
// Description:
//

#include <s32mem.h>
#include "SqlStmtSession.h"		//RSqlStatementSession

/**
Sends a request to the server to close the statement handle.
Closes the session object.
*/
void RSqlStatementSession::Close()
	{
	if(iDbSession && iHandle > 0)
		{
		(void)iDbSession->SendReceive(::MakeMsgCode(ESqlSrvStmtClose, ESqlSrvStatementHandle, iHandle));
		}
	iDbSession = NULL;
	iHandle = -1;
	}

/**
Binds the statement parameters and sends a request to the SQL server to move to the next record which satisfies the 
condition of the prepared SQL statement.
If there is a valid next record, the method transfers the column values from the server.

@param aParamBuf  It references RSqlBufFlat object where the parameter values are stored.
@param aColumnBuf It references RSqlBufFlat object where the column values will be stored.

@return KSqlAtRow,      the record data is ready for processing by the caller;
        KSqlAtEnd,      there is no more record data;
        KSqlErrBusy,    the database file is locked;
        KErrNoMemory,   an out of memory condition has occurred - the statement
                        will be reset;
        KSqlErrGeneral, a run-time error has occured - this function must not
                        be called again;        
        KSqlErrMisuse,  this function has been called after a previous call
                        returned KSqlAtEnd or KSqlErrGeneral.
        KSqlErrStmtExpired, the SQL statement has expired (if new functions or
                            collating sequences have been registered or if an
                            authorizer function has been added or changed);
*/
TInt RSqlStatementSession::BindNext(const RSqlBufFlat& aParamBuf, RSqlBufFlat& aColumnBuf)
	{
	TPtrC8 prmData(aParamBuf.BufDes());
	TIpcArgs ipcArgs;
	ipcArgs.Set(0, prmData.Length());
	ipcArgs.Set(1, &prmData);
	return DoBindNext(ESqlSrvStmtBindNext, ipcArgs, aColumnBuf);
	}

/**
Implements RSqlStatementSession::Next() and RSqlStatementSession::BindNext().
Sends a "Next" command to the server combined with optional "Bind" command.
In a single IPC call the statement parameters will be bound and the current row columns - returned.
If the client side flat buffer is not big enough, a second IPC call will be made after reallocating the buffer.

Usage of the IPC call arguments:
Arg 0: [out]		parameter buffer length in bytes
Arg 1: [out]		parameter buffer
Arg 2: [out]		column buffer length in bytes
Arg 3: [in/out]		column buffer

@see RSqlStatementSession::Next()
@see RSqlStatementSession::BindNext()
*/
TInt RSqlStatementSession::DoBindNext(TSqlSrvFunction aFunction, TIpcArgs& aIpcArgs, RSqlBufFlat& aColumnBuf)
	{
	aColumnBuf.Reset();
	aIpcArgs.Set(2, aColumnBuf.MaxSize());
	aIpcArgs.Set(3, &aColumnBuf.BufPtr());
	TInt err = DbSession().SendReceive(::MakeMsgCode(aFunction, ESqlSrvStatementHandle, iHandle), aIpcArgs);
	if(err > KSqlClientBufOverflowCode)
		{
		err = Retry(aColumnBuf, err - KSqlClientBufOverflowCode, ESqlColumnValuesBuf);
		if(err == KErrNone)
			{
			err = KSqlAtRow;	
			}
		}
	return err;
	}

/**
Sends a command to the server for retrieving parameter names or column names.

Usage of the IPC call arguments:
Arg 0: [out]		buffer length in bytes
Arg 1: [in/out]		buffer
*/	
TInt RSqlStatementSession::GetNames(TSqlSrvFunction aFunction, RSqlBufFlat& aNameBuf)
	{
	aNameBuf.Reset();
	TPtr8& ptr = aNameBuf.BufPtr();
	TInt err = DbSession().SendReceive(::MakeMsgCode(aFunction, ESqlSrvStatementHandle, iHandle), TIpcArgs(ptr.MaxLength(), &ptr));
	if(err > KSqlClientBufOverflowCode)
		{
		err = Retry(aNameBuf, err - KSqlClientBufOverflowCode, aFunction == ESqlSrvStmtColumnNames ? ESqlColumnNamesBuf : ESqlParamNamesBuf);
		}
	return err;
	}

/**
Sends a command to the server for retrieving specified data (aWhat parameter).

Usage of the IPC call arguments:
Arg 0: [out]		The type of the data to be retrieved
Arg 1: [in/out]		Data buffer
*/	
TInt RSqlStatementSession::Retry(RSqlBufFlat& aBufFlat, TInt aSize, TSqlBufFlatType aWhat)
	{
	aBufFlat.Reset();
	TInt err = aBufFlat.ReAlloc(aSize);
	if(err == KErrNone)
		{
		TPtr8& ptr = aBufFlat.BufPtr();
		err = DbSession().SendReceive(::MakeMsgCode(ESqlSrvStmtBufFlat, ESqlSrvStatementHandle, iHandle), TIpcArgs(aWhat, &ptr));
		}
	return err;	
	}

/**
Sends a command to the server for retrieving the declared types of columns

Usage of the IPC call arguments:
Arg 0: [out]		buffer length in bytes
Arg 1: [in/out]		buffer
*/	 
TInt RSqlStatementSession::GetDeclColumnTypes(RSqlBufFlat& aDeclColumnTypeBuf)
	{
	aDeclColumnTypeBuf.Reset();
	TPtr8& ptr = aDeclColumnTypeBuf.BufPtr();
	TInt err = DbSession().SendReceive(::MakeMsgCode(ESqlSrvStmtDeclColumnTypes, ESqlSrvStatementHandle, iHandle), TIpcArgs(ptr.MaxLength(), &ptr));	
	if(err > KSqlClientBufOverflowCode)
		{
		err = Retry(aDeclColumnTypeBuf, err - KSqlClientBufOverflowCode, ESqlDeclColumnTypesBuf);
		}
	return err;	
	}
