/*
*	©Copyright 2002,2003, Microsoft Corporation
*	Microsoft Confidential.
*	Written by Sergey Vasilevskiy, 2002-2003.
*/

/*
*	Trade Order database class that uses stored procedures for individual frames.
*/

#include "stdafx.h"

using namespace TPCE;

CTradeOrderDB::CTradeOrderDB(CDBConnection *pDBConn)
: CTxnHarnessDBBase(pDBConn)
{	
	int i;

	//Allocate one handle per stored procedure (frame)
	if (SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmtFrame1) != SQL_SUCCESS)
		ThrowError(CODBCERR::eAllocHandle, SQL_HANDLE_STMT, m_hdbc);
	if (SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmtFrame2) != SQL_SUCCESS)
		ThrowError(CODBCERR::eAllocHandle, SQL_HANDLE_STMT, m_hdbc);
	if (SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmtFrame3) != SQL_SUCCESS)
		ThrowError(CODBCERR::eAllocHandle, SQL_HANDLE_STMT, m_hdbc);
	if (SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc, &m_hstmtFrame4) != SQL_SUCCESS)
		ThrowError(CODBCERR::eAllocHandle, SQL_HANDLE_STMT, m_hdbc);

	//Bind input/output parameters for each stored procedure
	
	//Frame1 input
	i = 0;
	if (   //SQLBindParameter(m_hstmtFrame1, ++i, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &Frame1Output.status, 0, NULL)!=SQL_SUCCESS //sp return code
		 SQLBindParameter(m_hstmtFrame1, ++i, SQL_PARAM_INPUT, SQL_C_IDENT, SQL_IDENT, 0, 0, &Frame1Input.acct_id, 0, NULL)!=SQL_SUCCESS )
		ThrowError(CODBCERR::eBindParam, SQL_HANDLE_STMT, m_hstmtFrame1);
	//Frame1 output
	i = 0;
	if (   SQLBindCol(m_hstmtFrame1, ++i, SQL_C_IDENT, &Frame1Output.broker_id, cB_NAME_len+1, NULL) != SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame1, ++i, SQL_C_IDENT, &Frame1Output.cust_id, 0, NULL) != SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame1, ++i, SQL_C_CHAR, Frame1Output.acct_name, cCA_NAME_len+1, NULL) != SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame1, ++i, SQL_C_SLONG, &Frame1Output.tax_status, 0, NULL) != SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame1, ++i, SQL_C_CHAR, Frame1Output.cust_l_name, cL_NAME_len+1, NULL) != SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame1, ++i, SQL_C_CHAR, Frame1Output.cust_f_name, cF_NAME_len+1, NULL) != SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame1, ++i, SQL_C_CHAR, Frame1Output.tax_id, cTAX_ID_len+1, NULL) != SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame1, ++i, SQL_C_SLONG, &Frame1Output.cust_tier, 0, NULL) != SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame1, ++i, SQL_C_CHAR, Frame1Output.broker_name, cB_NAME_len+1, NULL) != SQL_SUCCESS
		)
		ThrowError(CODBCERR::eBindCol, SQL_HANDLE_STMT, m_hstmtFrame1);
	

	//Frame2 input
	i = 0;	
	if (   //SQLBindParameter(m_hstmtFrame2, ++i, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &Frame2Output.status, 0, NULL)!=SQL_SUCCESS //sp return code
		   SQLBindParameter(m_hstmtFrame2, ++i, SQL_PARAM_INPUT, SQL_C_IDENT, SQL_IDENT, 0, 0, &Frame2Input.acct_id, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame2, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cF_NAME_len+1, 0, Frame2Input.exec_f_name, cF_NAME_len+1, NULL) != SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame2, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cL_NAME_len+1, 0, Frame2Input.exec_l_name, cL_NAME_len+1, NULL) != SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame2, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cTAX_ID_len+1, 0, Frame2Input.exec_tax_id, cTAX_ID_len+1, NULL) != SQL_SUCCESS
		)
		ThrowError(CODBCERR::eBindParam, SQL_HANDLE_STMT, m_hstmtFrame2);
	//Frame2 output	
	i = 0;
	if ( SQLBindCol(m_hstmtFrame2, ++i, SQL_C_CHAR, &Frame2Output.ap_acl, cACL_len+1, NULL)!=SQL_SUCCESS )
		ThrowError(CODBCERR::eBindCol, SQL_HANDLE_STMT, m_hstmtFrame2);	
	

	//Frame3 input
	i = 0;
	if (   //SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &Frame3Output.status, 0, NULL)!=SQL_SUCCESS //sp return code
		   SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_IDENT, SQL_IDENT, 0, 0, &Frame3Input.acct_id, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_IDENT, SQL_IDENT, 0, 0, &Frame3Input.cust_id, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_TINYINT, 0, 0, &Frame3Input.cust_tier, 0, NULL)!=SQL_SUCCESS		
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_TINYINT, 0, 0, &Frame3Input.is_lifo, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cS_ISSUE_len+1, 0, Frame3Input.issue, cS_ISSUE_len+1, NULL) != SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cST_ID_len+1, 0, Frame3Input.st_pending_id, cST_ID_len+1, NULL) != SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cST_ID_len+1, 0, Frame3Input.st_submitted_id, cST_ID_len+1, NULL) != SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_TINYINT, 0, 0, &Frame3Input.tax_status, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &Frame3Input.trade_qty, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cTT_ID_len+1, 0, Frame3Input.trade_type_id, cTT_ID_len+1, NULL) != SQL_SUCCESS		
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_TINYINT, 0, 0, &Frame3Input.type_is_margin, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cCO_NAME_len+1, 0, Frame3Input.co_name, cCO_NAME_len+1, &m_Frame3_CO_NAME_Ind) != SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &Frame3Input.requested_price, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame3, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cSYMBOL_len+1, 0, Frame3Input.symbol, cSYMBOL_len+1, &m_Frame3_SYMBOL_Ind) != SQL_SUCCESS		
		)
		ThrowError(CODBCERR::eBindParam, SQL_HANDLE_STMT, m_hstmtFrame3);
	//Frame3 output
	i = 0;
	if (   SQLBindCol(m_hstmtFrame3, ++i, SQL_C_CHAR, Frame3Output.co_name, cCO_NAME_len+1, NULL) != SQL_SUCCESS
        || SQLBindCol(m_hstmtFrame3, ++i, SQL_C_DOUBLE, &Frame3Output.requested_price, 0, NULL)!=SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame3, ++i, SQL_C_CHAR, Frame3Output.symbol, cSYMBOL_len+1, NULL) != SQL_SUCCESS
        || SQLBindCol(m_hstmtFrame3, ++i, SQL_C_DOUBLE, &Frame3Output.buy_value, 0, NULL)!=SQL_SUCCESS
        || SQLBindCol(m_hstmtFrame3, ++i, SQL_C_DOUBLE, &Frame3Output.charge_amount, 0, NULL)!=SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame3, ++i, SQL_C_DOUBLE, &Frame3Output.comm_rate, 0, NULL)!=SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame3, ++i, SQL_C_DOUBLE, &Frame3Output.acct_assets, 0, NULL)!=SQL_SUCCESS
        || SQLBindCol(m_hstmtFrame3, ++i, SQL_C_DOUBLE, &Frame3Output.market_price, 0, NULL)!=SQL_SUCCESS
        || SQLBindCol(m_hstmtFrame3, ++i, SQL_C_CHAR, Frame3Output.s_name, cS_NAME_len+1, NULL) != SQL_SUCCESS
        || SQLBindCol(m_hstmtFrame3, ++i, SQL_C_DOUBLE, &Frame3Output.sell_value, 0, NULL)!=SQL_SUCCESS
        || SQLBindCol(m_hstmtFrame3, ++i, SQL_C_CHAR, Frame3Output.status_id, cST_ID_len+1, NULL)!=SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame3, ++i, SQL_C_DOUBLE, &Frame3Output.tax_amount, 0, NULL)!=SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame3, ++i, SQL_C_SLONG, &Frame3Output.type_is_market, 0, NULL)!=SQL_SUCCESS
		|| SQLBindCol(m_hstmtFrame3, ++i, SQL_C_SLONG, &Frame3Output.type_is_sell, 0, NULL)!=SQL_SUCCESS
		)
		ThrowError(CODBCERR::eBindCol, SQL_HANDLE_STMT, m_hstmtFrame3);
	

	//Frame 4 input	
	i = 0;
	if (   //SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &Frame4Output.status, 0, NULL)!=SQL_SUCCESS //sp return code
		   SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_IDENT, SQL_IDENT, 0, 0, &Frame4Input.acct_id, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_IDENT, SQL_IDENT, 0, 0, &Frame4Input.broker_id, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &Frame4Input.charge_amount, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &Frame4Input.comm_amount, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, cEXEC_NAME_len+1, 0, Frame4Input.exec_name, cEXEC_NAME_len+1, NULL) != SQL_SUCCESS
		//|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &Frame4Input.high_limit, 0, NULL)!=SQL_SUCCESS
		//|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &Frame4Input.low_limit, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_TINYINT, 0, 0, &Frame4Input.is_cash, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_TINYINT, 0, 0, &Frame4Input.is_lifo, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, 0, 0, &Frame4Input.requested_price, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cST_ID_len+1, 0, Frame4Input.status_id, cST_ID_len+1, NULL) != SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cSYMBOL_len+1, 0, Frame4Input.symbol, cSYMBOL_len+1, NULL) != SQL_SUCCESS		
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &Frame4Input.trade_qty, 0, NULL)!=SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, cTT_ID_len+1, 0, Frame4Input.trade_type_id, cTT_ID_len+1, NULL) != SQL_SUCCESS
		|| SQLBindParameter(m_hstmtFrame4, ++i, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_TINYINT, 0, 0, &Frame4Input.type_is_market, 0, NULL)!=SQL_SUCCESS
		)
		ThrowError(CODBCERR::eBindParam, SQL_HANDLE_STMT, m_hstmtFrame4);
	//Frame 4 output 
	i = 0;
	if ( SQLBindCol(m_hstmtFrame4, ++i, SQL_C_IDENT, &Frame4Output.trade_id, 0, NULL)!=SQL_SUCCESS )
		ThrowError(CODBCERR::eBindCol, SQL_HANDLE_STMT, m_hstmtFrame4);
};

//Destructor
CTradeOrderDB::~CTradeOrderDB()
{
	SQLFreeHandle(SQL_HANDLE_STMT, m_hstmtFrame1);
	SQLFreeHandle(SQL_HANDLE_STMT, m_hstmtFrame2);
	SQLFreeHandle(SQL_HANDLE_STMT, m_hstmtFrame3);
	SQLFreeHandle(SQL_HANDLE_STMT, m_hstmtFrame4);
}

void CTradeOrderDB::DoTradeOrderFrame1(const TTradeOrderFrame1Input *pFrame1Input, PTradeOrderFrame1Output pFrame1Output)
{
	int rc;
	int i;

	Frame1Input = *pFrame1Input;	//input parameter
	
	rc = SQLExecDirect(m_hstmtFrame1, (SQLCHAR*)"{call TradeOrderFrame1(?)}", SQL_NTS);
	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
		ThrowError(CODBCERR::eExecDirect, SQL_HANDLE_STMT, m_hstmtFrame1, "DoTradeOrderFrame1");

	if ( (rc = SQLFetch(m_hstmtFrame1)) == SQL_ERROR)
		ThrowError(CODBCERR::eFetch, SQL_HANDLE_STMT, m_hstmtFrame1, "DoTradeOrderFrame1");
	
	if (rc != SQL_NO_DATA)	// check whether SQLFetch returned any rows
	{
		// Strip trailing spaces at the end of customer info,
		// so that the Frame 2 check in TxnHarnessTradeOrder works.

		// Customer first name
		for (i = sizeof(Frame1Output.cust_f_name) - 2;	// walk back from the end
			Frame1Output.cust_f_name[i]==' ' && i>0;
			--i);
		Frame1Output.cust_f_name[i + 1] = '\0';

		// Customer last name
		for (i = sizeof(Frame1Output.cust_l_name) - 2;	// walk back from the end
			Frame1Output.cust_l_name[i]==' ' && i>0;
			--i);
		Frame1Output.cust_l_name[i + 1] = '\0';

		// Customer tax id
		for (i = sizeof(Frame1Output.tax_id) - 2;	// walk back from the end
			Frame1Output.tax_id[i]==' ' && i>0;
			--i);
		Frame1Output.tax_id[i + 1] = '\0';

		//copy output parameters back
		*pFrame1Output = Frame1Output;	//invoke default assignment operator
		pFrame1Output->num_found = 1;
	}
	else
	{
		pFrame1Output->num_found = 0;
	}

	// Need two SQLFreeStmt calls for some reason to clean the statement
	// handle properly after the server sent "Transaction count incorrect after batch" message
	// with the result set.
	//
	rc = SQLFreeStmt(m_hstmtFrame1, SQL_CLOSE);
	rc = SQLFreeStmt(m_hstmtFrame1, SQL_CLOSE);
}

void CTradeOrderDB::DoTradeOrderFrame2(const TTradeOrderFrame2Input *pFrame2Input, PTradeOrderFrame2Output pFrame2Output)
{
	int rc;

	Frame2Input = *pFrame2Input;	//invoke default assignment operator

	rc = SQLExecDirect(m_hstmtFrame2, (SQLCHAR*)"{call TradeOrderFrame2(?, ?, ?, ?)}", SQL_NTS);
	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
		ThrowError(CODBCERR::eExecDirect, SQL_HANDLE_STMT, m_hstmtFrame2, "DoTradeOrderFrame2");

	if ( (rc = SQLFetch(m_hstmtFrame2)) == SQL_ERROR)
		ThrowError(CODBCERR::eFetch, SQL_HANDLE_STMT, m_hstmtFrame2, "DoTradeOrderFrame2");

	if (rc != SQL_NO_DATA)	// check whether SQLFetch returned any rows
	{
		//copy output parameters back
		*pFrame2Output = Frame2Output;
	}

	// Need two SQLFreeStmt calls for some reason to clean the statement
	// handle properly after the server sent "Transaction count incorrect after batch" message
	// with the result set.
	//
	rc = SQLFreeStmt(m_hstmtFrame2, SQL_CLOSE);
	rc = SQLFreeStmt(m_hstmtFrame2, SQL_CLOSE);
}

void CTradeOrderDB::DoTradeOrderFrame3(const TTradeOrderFrame3Input *pFrame3Input, PTradeOrderFrame3Output pFrame3Output)
{
	int i;
	int rc;

	Frame3Input = *pFrame3Input;	//invoke default assignment operator
	//set up proper indicator variable values
	if (Frame3Input.co_name[0] == '\0')
	{
		m_Frame3_CO_NAME_Ind = SQL_NULL_DATA;
	}
	else
	{
		m_Frame3_CO_NAME_Ind = SQL_NTS;
	}

	if (Frame3Input.symbol[0] == '\0')
	{
		m_Frame3_SYMBOL_Ind = SQL_NULL_DATA;
	}
	else
	{
		m_Frame3_SYMBOL_Ind = SQL_NTS;
	}
	
	rc = SQLExecDirect(m_hstmtFrame3, 
		(SQLCHAR*)"{call TradeOrderFrame3(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}", SQL_NTS);
	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
		ThrowError(CODBCERR::eExecDirect, SQL_HANDLE_STMT, m_hstmtFrame3, "DoTradeOrderFrame3");

	if ( SQLFetch(m_hstmtFrame3) == SQL_ERROR)
		ThrowError(CODBCERR::eFetch, SQL_HANDLE_STMT, m_hstmtFrame3, "DoTradeOrderFrame3");

	//check returned indicator variables
	//if (m_Frame3_CUST_ASSETS_Ind == SQL_NULL_DATA)
	//	Frame3Output.cust_assets = 0;	// this can happen if the loader didn't generate any holdings for the account

	//if (m_Frame3_TAX_AMOUNT_Ind == SQL_NULL_DATA)
	//	Frame3Output.tax_amount = 0;

	//copy symbol but don't include ODBC space padding at the end
	for (i = 0; 
		Frame3Output.symbol[i]!='\0' && Frame3Output.symbol[i]!=' ' && i<sizeof(Frame3Output.symbol);
		++i);
	Frame3Output.symbol[i] = '\0';
	//copy output parameters back
	*pFrame3Output = Frame3Output;	
	
	// Need two SQLFreeStmt calls for some reason to clean the statement
	// handle properly after the server sent "Transaction count incorrect after batch" message
	// with the result set.
	//
	rc = SQLFreeStmt(m_hstmtFrame3, SQL_CLOSE);
	rc = SQLFreeStmt(m_hstmtFrame3, SQL_CLOSE);
}

void CTradeOrderDB::DoTradeOrderFrame4(const TTradeOrderFrame4Input *pFrame4Input, PTradeOrderFrame4Output pFrame4Output)
{
	int rc;

	Frame4Input = *pFrame4Input;	//invoke default assignment operator

	rc = SQLExecDirect(m_hstmtFrame4, 
		(SQLCHAR*)"{call TradeOrderFrame4(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}", SQL_NTS);
	if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)
		ThrowError(CODBCERR::eExecDirect, SQL_HANDLE_STMT, m_hstmtFrame4, "DoTradeOrderFrame4");

	if ( SQLFetch(m_hstmtFrame4) == SQL_ERROR)
		ThrowError(CODBCERR::eFetch, SQL_HANDLE_STMT, m_hstmtFrame4, "DoTradeOrderFrame4");

	//copy output parameters back
	*pFrame4Output = Frame4Output;

	// Need two SQLFreeStmt calls for some reason to clean the statement
	// handle properly after the server sent "Transaction count incorrect after batch" message
	// with the result set.
	//
	rc = SQLFreeStmt(m_hstmtFrame4, SQL_CLOSE);
	rc = SQLFreeStmt(m_hstmtFrame4, SQL_CLOSE);
}

void CTradeOrderDB::DoTradeOrderFrame5()
{
	//Rollback the transaction on this connection
	Rollback();
}

void CTradeOrderDB::DoTradeOrderFrame6()
{
	//Commit the transaction on this connection
	CommitTransaction();
}

void CTradeOrderDB::Cleanup(void* pException)
{
	SQLCloseCursor(m_hstmtFrame1);
	SQLCloseCursor(m_hstmtFrame2);
	SQLCloseCursor(m_hstmtFrame3);
	SQLCloseCursor(m_hstmtFrame4);
}
