blob: 67c453d4e78477137e0d22bc41a3729d6539128c [file] [log] [blame]
/*************************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**************************************************************************/
#include "process.h"
#include "CStmt.h"
#include "tdm_odbcDrvMsg.h"
#include "DrvrNet.h"
#include "DrvrSrvr.h"
#include "DrvrGlobal.h"
#include "nskieee.h"
#include "sqlcli.h"
#include "swap.h"
#include "csconvert.h"
#include "DiagFunctions.h"
using namespace ODBC;
DWORD wait_for_event(HANDLE hEvent,long timeout);
// Implements the member functions of CStmt
CStmt::CStmt(SQLHANDLE InputHandle) : CHandle(SQL_HANDLE_STMT, InputHandle)
{
m_AsyncThread = NULL;
m_ThreadStatus = SQL_SUCCESS;
m_StmtEvent = NULL;
m_SyncThread = NULL;
m_StmtName[0] = '\0';
m_CursorName[0] = '\0';
sprintf(m_StmtLabel, "SQL_CUR_%ld", m_HandleNumber);
strcpy(m_StmtLabelOrg, m_StmtLabel);
m_ConnectHandle = (CConnect *)m_InputHandle;
m_ARDDesc = NULL;
m_IRDDesc = NULL;
m_APDDesc = NULL;
m_IPDDesc = NULL;
m_AppParamDesc = m_APDDesc;
m_AppRowDesc = m_ARDDesc;
m_ImpParamDesc = m_IPDDesc;
m_ImpRowDesc = m_IRDDesc;
m_AsyncEnable = m_ConnectHandle->m_AsyncEnable;
m_Concurrency = m_ConnectHandle->m_Concurrency;
m_CursorType = m_ConnectHandle->m_CursorType;
m_CursorScrollable = SQL_NONSCROLLABLE;
m_CursorSensitivity = SQL_UNSPECIFIED;
m_EnableAutoIPD = m_ConnectHandle->m_AutoIPD;
m_FetchBookmarkPtr = NULL;
m_CursorHoldable = SQL_NONHOLDABLE; // non-holdable is default
m_KeysetSize = SQL_KEYSET_SIZE_DEFAULT;
m_MaxLength = m_ConnectHandle->m_MaxLength;
m_MaxRows = m_ConnectHandle->m_MaxRows; // Return all rows
m_MetadataId = m_ConnectHandle->m_MetadataId;
m_Noscan = m_ConnectHandle->m_Noscan;
m_QueryTimeout = m_ConnectHandle->m_QueryTimeout;
m_RetrieveData = SQL_RD_DEFAULT;
m_RowNumber = 0;
m_SimulateCursor = m_ConnectHandle->m_SimulateCursor;
m_UseBookmarks = m_ConnectHandle->m_UseBookmarks;
m_CurrentOdbcAPI = SQL_API_SQLALLOCHANDLE;
m_CurrentParam = -1;
m_CurrentRow = -1;
m_CurrentParamStatus = 0;
m_InputValueList._buffer = 0;
m_InputValueList._length = 0;
m_DataAtExecData.dataValue._length = 0;
m_DataAtExecData.dataValue._buffer = NULL;
m_DataAtExecDataBufferSize = 0;
m_ParamBuffer = NULL;
m_RowsFetched = -1;
m_CurrentRowFetched = 0;
m_CurrentRowInRowset = 0;
m_RowsetSize = 0;
m_ResultsetRowsFetched = 0;
m_NumResultCols = 0;
m_NumParams = 0;
m_StmtState = STMT_ALLOCATED;
m_StmtPrepared = FALSE;
EnterCriticalSection(&m_ConnectHandle->m_CSObject);
m_ConnectHandle->m_StmtCollect.push_back(this);
LeaveCriticalSection(&m_ConnectHandle->m_CSObject);
m_RowStatusArray = NULL;
m_CurrentFetchType = 0;
m_AsyncCanceled = FALSE;
m_RowCount = -1;
m_FetchDataValue.numberOfElements = 0;
m_FetchDataValue.numberOfRows = 0;
m_FetchDataValue.rowAddress = NULL;
m_SelectRowsets = m_ConnectHandle->m_SelectRowsets;
m_FetchBufferSize = m_ConnectHandle->m_FetchBufferSize;
m_CatalogName[0] = '\0';
m_SchemaName[0] = '\0';
m_TableName[0] = '\0';
m_ColumnName[0] = '\0';
m_TableType[0] = '\0';
m_FKCatalogName[0] = '\0';
m_FKSchemaName[0] = '\0';
m_FKTableName[0] = '\0';
m_outputDataValue._length = 0;
m_outputDataValue._buffer = 0;
m_StmtQueryType = 0;
m_StmtHandle = 0;
m_APIDecision = true;
m_InputParams = NULL;
m_OutputColumns = NULL;
m_isClosed = false;
m_intStmtType = TYPE_UNKNOWN;
m_ColumnIndexes = NULL;
m_SwapInfo = NULL;
m_SwapInfo_NumRows = 0;
m_spjNumResultSets = 0;
m_spjResultSets = NULL;
m_spjCurrentResultSetIndex = 0;
m_spjInputParamDesc._length = 0;
m_spjInputParamDesc._buffer = NULL;
m_spjOutputParamDesc._length = 0;
m_spjOutputParamDesc._buffer = NULL;
m_CancelCalled = false;
}
CStmt::~CStmt()
{
CHANDLECOLLECT::iterator i;
DWORD preFetchThreadStatus;
if (this->m_preFetchThread.m_Thread != NULL)
{
GetExitCodeThread(this->m_preFetchThread.m_Thread, &preFetchThreadStatus);
if (preFetchThreadStatus == STILL_ACTIVE)
WaitForSingleObject(this->m_preFetchThread.m_Thread,INFINITE);
GetExitCodeThread(this->m_preFetchThread.m_Thread, &preFetchThreadStatus);
CloseHandle(this->m_preFetchThread.m_Thread);
this->m_preFetchThread.m_Thread = NULL;
}
Close(SQL_DROP);
clearError();
if (m_ARDDesc != NULL)
delete m_ARDDesc;
if (m_IRDDesc != NULL)
delete m_IRDDesc;
if (m_APDDesc != NULL)
delete m_APDDesc;
if (m_IPDDesc != NULL)
delete m_IPDDesc;
if (m_AsyncThread != NULL)
CloseHandle(m_AsyncThread);
if (m_StmtEvent != NULL)
CloseHandle(m_StmtEvent);
if (m_InputValueList._buffer != NULL)
delete m_InputValueList._buffer;
if (m_FetchDataValue.rowAddress != NULL )
delete[] m_FetchDataValue.rowAddress;
if (m_outputDataValue._length != 0 &&
m_outputDataValue._buffer != NULL)
delete m_outputDataValue._buffer;
if (m_InputParams != NULL)
delete m_InputParams;
if (m_OutputColumns != NULL)
delete m_OutputColumns;
if (m_ColumnIndexes != NULL)
delete[] m_ColumnIndexes;
if (m_SwapInfo != NULL)
{
for (int r = 0; r < m_SwapInfo_NumRows; r++)
{
if (m_SwapInfo[r] != NULL)
delete[] (m_SwapInfo[r]);
}
delete[] m_SwapInfo;
m_SwapInfo = NULL;
m_SwapInfo_NumRows = 0;
}
if(m_spjResultSets != NULL)
delete[] m_spjResultSets;
if( m_spjInputParamDesc._length != 0 &&
m_spjInputParamDesc._buffer != NULL)
delete [] m_spjInputParamDesc._buffer;
if( m_spjOutputParamDesc._length != 0 &&
m_spjOutputParamDesc._buffer != NULL)
delete [] m_spjOutputParamDesc._buffer;
// Remove this from StmtCollection in Connection
EnterCriticalSection(&m_ConnectHandle->m_CSObject);
for (i = m_ConnectHandle->m_StmtCollect.begin() ; i != m_ConnectHandle->m_StmtCollect.end() ; ++i)
{
if ((*i) == this)
{
m_ConnectHandle->m_StmtCollect.erase(i);
break;
}
}
LeaveCriticalSection(&m_ConnectHandle->m_CSObject);
}
void CStmt::InitInputValueList()
{
if (m_ParamBuffer != NULL)
delete m_ParamBuffer;
m_ParamBuffer = NULL;
if (m_InputValueList._buffer != NULL)
delete m_InputValueList._buffer;
m_InputValueList._buffer = 0;
m_InputValueList._length = 0;
m_CurrentParam = -1;
m_CurrentRow = -1;
m_CurrentParamStatus = 0;
m_DataAtExecData.dataValue._length = 0;
if (m_DataAtExecData.dataValue._buffer != NULL)
delete m_DataAtExecData.dataValue._buffer;
m_DataAtExecData.dataValue._buffer = NULL;
m_DataAtExecDataBufferSize = 0;
if (m_FetchDataValue.rowAddress != NULL )
delete[] m_FetchDataValue.rowAddress;
m_FetchDataValue.numberOfElements = 0;
m_FetchDataValue.numberOfRows = 0;
m_FetchDataValue.rowAddress = NULL;
if (m_ColumnIndexes != NULL)
{
delete[] m_ColumnIndexes;
m_ColumnIndexes = NULL;
}
if (m_SwapInfo != NULL)
{
for (int r = 0; r < m_SwapInfo_NumRows; r++)
{
if (m_SwapInfo[r] != NULL)
delete[] (m_SwapInfo[r]);
}
delete[] m_SwapInfo;
m_SwapInfo = NULL;
m_SwapInfo_NumRows = 0;
}
}
void CStmt::InitParamColumnList()
{
m_StmtQueryType = -1;
m_StmtHandle = 0;
if (m_InputParams != NULL)
delete m_InputParams;
m_InputParams = NULL;
if (m_OutputColumns != NULL)
delete m_OutputColumns;
m_OutputColumns = NULL;
}
SQLRETURN CStmt::Close(SQLUSMALLINT Option)
{
SQLRETURN rc = SQL_SUCCESS;
if (m_ConnectHandle->getConnectionStatus() == SQL_CD_TRUE)
{
clearError();
setDiagRec(DRIVER_ERROR, IDS_08_S01);
rc = SQL_SUCCESS_WITH_INFO;
}
else if(!(m_isClosed && Option == SQL_CLOSE))
{
m_SrvrCallContext.odbcAPI = SQL_API_SQLFREESTMT;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.statementTimeout = m_QueryTimeout;
m_SrvrCallContext.u.closeParams.stmtLabel = m_StmtLabel;
m_SrvrCallContext.u.closeParams.option = Option;
rc = ThreadControlProc(&m_SrvrCallContext);
}
if (m_AsyncThread != NULL)
{
// TerminateThread
CloseHandle(m_AsyncThread);
}
m_ThreadStatus = SQL_SUCCESS;
m_RowsFetched = -1;
m_CurrentRowFetched = 0;
m_CurrentRowInRowset = 0;
m_RowsetSize = 0;
m_ResultsetRowsFetched = 0;
m_RowNumber = 0;
m_RowStatusArray = NULL;
m_CurrentFetchType = 0;
m_AsyncCanceled = FALSE;
m_isClosed = true;
return rc;
}
SQLRETURN CStmt::initialize()
{
m_ARDDesc = new CDesc(m_InputHandle, SQL_ATTR_APP_ROW_DESC, SQL_DESC_ALLOC_AUTO);
m_IRDDesc = new CDesc(m_InputHandle, SQL_ATTR_IMP_ROW_DESC, SQL_DESC_ALLOC_AUTO, this);
m_APDDesc = new CDesc(m_InputHandle, SQL_ATTR_APP_PARAM_DESC, SQL_DESC_ALLOC_AUTO);
m_IPDDesc = new CDesc(m_InputHandle, SQL_ATTR_IMP_PARAM_DESC, SQL_DESC_ALLOC_AUTO, this);
m_AppParamDesc = m_APDDesc;
m_AppRowDesc = m_ARDDesc;
m_ImpParamDesc = m_IPDDesc;
m_ImpRowDesc = m_IRDDesc;
if (m_ARDDesc == NULL || m_IRDDesc == NULL || m_APDDesc == NULL || m_IPDDesc == NULL)
{
setDiagRec(DRIVER_ERROR, IDS_HY_001);
return SQL_ERROR;
}
if (m_StmtEvent == NULL)
{
m_StmtEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_StmtEvent == NULL)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "initialize - CreateEvent()");
return SQL_ERROR;
}
}
return SQL_SUCCESS;
}
SQLRETURN CStmt::SetStmtAttr(SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER StringLength)
{
SQLRETURN rc = SQL_SUCCESS;
unsigned long retCode = SQL_SUCCESS;
SQLUINTEGER Value;
clearError();
m_CurrentOdbcAPI = SQL_API_SQLSETSTMTATTR;
switch (Attribute)
{
case SQL_ATTR_APP_PARAM_DESC:
if (ValuePtr == SQL_NULL_HDESC)
m_AppParamDesc = m_APDDesc;
else
m_AppParamDesc = (CDesc *)ValuePtr;
break;
case SQL_ATTR_APP_ROW_DESC:
if (ValuePtr == SQL_NULL_HDESC)
m_AppRowDesc = m_ARDDesc;
else
m_AppRowDesc = (CDesc *)ValuePtr;
ValuePtr = (SQLPOINTER)m_AppRowDesc;
break;
case SQL_ATTR_ASYNC_ENABLE:
m_AsyncEnable = (SQLUINTEGER)ValuePtr;
break;
case SQL_ATTR_CONCURRENCY:
// Added code to send to server about the SQL_ATTR_CONCURRENCY to perform
// "CONTROL QUERY DEFAULT CURSOR_READONLY 'TRUE or FALSE'" based on
// SQL_CONCUR_READ_ONLY or SQL_CONCUR_LOCK attributes.
Value = (SQLUINTEGER)ValuePtr;
if (m_ConnectHandle->getConnectionStatus() == SQL_CD_TRUE)
{
clearError();
setDiagRec(DRIVER_ERROR, IDS_08_S01, -20005);
return SQL_ERROR;
}
else
rc = m_ConnectHandle->SetConnectAttr(Attribute, (SQLUINTEGER)ValuePtr, NULL);
if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
{
switch (Value)
{
case SQL_CONCUR_READ_ONLY:
m_CursorSensitivity = SQL_INSENSITIVE;
break;
case SQL_CONCUR_LOCK:
m_CursorSensitivity = SQL_SENSITIVE;
break;
case SQL_CONCUR_ROWVER:
case SQL_CONCUR_VALUES:
m_CursorSensitivity = SQL_SENSITIVE;
retCode = IDS_01_S02;
Value = SQL_CONCUR_LOCK;
rc = SQL_SUCCESS_WITH_INFO;
break;
default:
retCode = IDS_HY_024;
rc = SQL_ERROR;
}
if (rc != SQL_ERROR)
m_Concurrency = Value;
}
break;
case SQL_ATTR_CURSOR_HOLDABLE:
m_CursorHoldable = (SQLUINTEGER)ValuePtr;
break;
case SQL_ATTR_CURSOR_SCROLLABLE:
if ((SQLUINTEGER)ValuePtr == SQL_NONSCROLLABLE)
m_CursorScrollable = (SQLUINTEGER)ValuePtr;
else
{
m_CursorScrollable = SQL_NONSCROLLABLE;
retCode = IDS_01_S02;
rc = SQL_SUCCESS_WITH_INFO;
}
break;
case SQL_ATTR_CURSOR_SENSITIVITY:
Value = (SQLUINTEGER)ValuePtr;
switch (Value)
{
case SQL_UNSPECIFIED:
case SQL_SENSITIVE:
m_Concurrency = SQL_CONCUR_LOCK;
break;
case SQL_INSENSITIVE:
m_Concurrency = SQL_CONCUR_READ_ONLY;
break;
default:
retCode = IDS_HY_024;
rc = SQL_ERROR;
break;
}
if (rc != SQL_ERROR)
m_CursorSensitivity = Value;
break;
case SQL_ATTR_CURSOR_TYPE:
Value = (SQLUINTEGER)ValuePtr;
if (Value == SQL_CURSOR_FORWARD_ONLY)
m_CursorType = Value;
else
{
m_CursorType = SQL_CURSOR_FORWARD_ONLY;
retCode = IDS_01_S02;
rc = SQL_SUCCESS_WITH_INFO;
}
break;
case SQL_ATTR_ENABLE_AUTO_IPD:
m_EnableAutoIPD = (SQLUINTEGER)ValuePtr;
break;
case SQL_ATTR_FETCH_BOOKMARK_PTR:
m_FetchBookmarkPtr = ValuePtr;
break;
case SQL_ATTR_KEYSET_SIZE:
m_KeysetSize = (SQLULEN)ValuePtr;
break;
case SQL_ATTR_MAX_LENGTH:
m_MaxLength = (SQLULEN)ValuePtr;
break;
case SQL_ATTR_MAX_ROWS:
m_MaxRows = (SQLULEN)ValuePtr;
break;
case SQL_ATTR_METADATA_ID:
m_MetadataId = (SQLUINTEGER)ValuePtr;
break;
case SQL_ATTR_NOSCAN:
m_Noscan = (SQLUINTEGER)ValuePtr;
break;
case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
rc = m_AppParamDesc->SetDescField(0, SQL_DESC_BIND_OFFSET_PTR, ValuePtr, StringLength);
break;
case SQL_ATTR_PARAM_BIND_TYPE:
rc = m_AppParamDesc->SetDescField(0, SQL_DESC_BIND_TYPE, ValuePtr, StringLength);
break;
case SQL_ATTR_PARAM_OPERATION_PTR:
rc = m_AppParamDesc->SetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, StringLength);
break;
case SQL_ATTR_PARAM_STATUS_PTR:
rc = m_ImpParamDesc->SetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, StringLength);
break;
case SQL_ATTR_PARAMS_PROCESSED_PTR:
rc = m_ImpParamDesc->SetDescField(0, SQL_DESC_ROWS_PROCESSED_PTR, ValuePtr, StringLength);
break;
case SQL_ATTR_PARAMSET_SIZE:
rc = m_AppParamDesc->SetDescField(0, SQL_DESC_ARRAY_SIZE, ValuePtr, StringLength);
break;
case SQL_ATTR_QUERY_TIMEOUT:
m_QueryTimeout = (SQLUINTEGER)ValuePtr;
if(m_QueryTimeout != 0 && m_QueryTimeout < 30)
m_QueryTimeout = 30;
break;
case SQL_ATTR_RETRIEVE_DATA:
m_RetrieveData = (SQLUINTEGER)ValuePtr;
break;
case SQL_ATTR_ROW_ARRAY_SIZE:
case SQL_ROWSET_SIZE:
rc = m_AppRowDesc->SetDescField(0, SQL_DESC_ARRAY_SIZE, ValuePtr, StringLength);
break;
case SQL_ATTR_ROW_BIND_OFFSET_PTR:
rc = m_AppRowDesc->SetDescField(0, SQL_DESC_BIND_OFFSET_PTR, ValuePtr, StringLength);
break;
case SQL_ATTR_ROW_BIND_TYPE:
rc = m_AppRowDesc->SetDescField(0, SQL_DESC_BIND_TYPE, ValuePtr, StringLength);
break;
case SQL_ATTR_ROW_OPERATION_PTR:
rc = m_AppRowDesc->SetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, StringLength);
break;
case SQL_ATTR_ROW_STATUS_PTR:
rc = m_ImpRowDesc->SetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, StringLength);
break;
case SQL_ATTR_ROWS_FETCHED_PTR:
rc = m_ImpRowDesc->SetDescField(0, SQL_DESC_ROWS_PROCESSED_PTR, ValuePtr, StringLength);
break;
case SQL_ATTR_SIMULATE_CURSOR:
m_SimulateCursor = (SQLUINTEGER)ValuePtr;
break;
case SQL_ATTR_USE_BOOKMARKS:
Value = (SQLUINTEGER)ValuePtr;
if (Value == SQL_UB_ON)
{
m_UseBookmarks = SQL_UB_OFF;
retCode = IDS_01_S02;
rc = SQL_SUCCESS_WITH_INFO;
}
else
m_UseBookmarks = Value;
break;
case SQL_ATTR_FETCH_BUFFER_SIZE:
m_FetchBufferSize = (SQLINTEGER)ValuePtr;
if (m_FetchBufferSize < 0)
m_FetchBufferSize = 0;
m_FetchBufferSize *= 1024;
break;
case SQL_ATTR_ROW_NUMBER:
case SQL_ATTR_IMP_PARAM_DESC:
case SQL_ATTR_IMP_ROW_DESC:
default:
retCode = IDS_HY_092;
rc = SQL_ERROR;
break;
}
if (retCode != SQL_SUCCESS)
setDiagRec(DRIVER_ERROR, retCode);
return rc;
}
SQLRETURN CStmt::GetStmtAttr(SQLINTEGER Attribute, SQLPOINTER ValuePtr, SQLINTEGER BufferLength,
SQLINTEGER *StringLengthPtr)
{
SQLRETURN rc = SQL_SUCCESS;
RETURN_VALUE_STRUCT retValue;
BOOL DescAttr;
SQLUSMALLINT *ArrayStatusPtr;
DescAttr = FALSE;
retValue.dataType = DRVR_PENDING;
retValue.u.strPtr = NULL;
clearError();
m_CurrentOdbcAPI = SQL_API_SQLGETSTMTATTR;
switch (Attribute)
{
case SQL_ATTR_APP_PARAM_DESC:
retValue.u.pValue = m_AppParamDesc;
retValue.dataType = SQL_IS_POINTER;
break;
case SQL_ATTR_APP_ROW_DESC:
retValue.u.pValue = m_AppRowDesc;
retValue.dataType = SQL_IS_POINTER;
break;
case SQL_ATTR_ASYNC_ENABLE:
retValue.u.u32Value = m_AsyncEnable;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_CONCURRENCY:
retValue.u.u32Value = m_Concurrency;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_CURSOR_HOLDABLE:
retValue.u.u32Value = m_CursorHoldable;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_CURSOR_SCROLLABLE:
retValue.u.u32Value = m_CursorScrollable;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_CURSOR_SENSITIVITY:
retValue.u.u32Value = m_CursorSensitivity;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_CURSOR_TYPE:
retValue.u.u32Value = m_CursorType;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_ENABLE_AUTO_IPD:
retValue.u.u32Value = m_EnableAutoIPD;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_FETCH_BOOKMARK_PTR:
retValue.u.pValue = m_FetchBookmarkPtr;
retValue.dataType = SQL_IS_POINTER;
break;
case SQL_ATTR_IMP_PARAM_DESC:
retValue.u.pValue = m_ImpParamDesc;
retValue.dataType = SQL_IS_POINTER;
break;
case SQL_ATTR_IMP_ROW_DESC:
retValue.u.pValue = m_ImpRowDesc;
retValue.dataType = SQL_IS_POINTER;
break;
case SQL_ATTR_KEYSET_SIZE:
#ifdef _WIN64
retValue.u.s64Value = m_KeysetSize;
retValue.dataType = SQL_C_UBIGINT;
#else
retValue.u.u32Value = m_KeysetSize;
retValue.dataType = SQL_IS_UINTEGER;
#endif
break;
case SQL_ATTR_MAX_LENGTH:
#ifdef _WIN64
retValue.u.s64Value = m_MaxLength;
retValue.dataType = SQL_C_UBIGINT;
#else
retValue.u.u32Value = m_MaxLength;
retValue.dataType = SQL_IS_UINTEGER;
#endif
break;
case SQL_ATTR_MAX_ROWS:
#ifdef _WIN64
retValue.u.s64Value = m_MaxRows;
retValue.dataType = SQL_C_UBIGINT;
#else
retValue.u.u32Value = m_MaxRows;
retValue.dataType = SQL_IS_UINTEGER;
#endif
break;
case SQL_ATTR_METADATA_ID:
retValue.u.u32Value = m_MetadataId;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_NOSCAN:
retValue.u.u32Value = m_Noscan;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_PARAM_BIND_OFFSET_PTR:
rc = m_AppParamDesc->GetDescField(0, SQL_DESC_BIND_OFFSET_PTR, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_PARAM_BIND_TYPE:
rc = m_AppParamDesc->GetDescField(0, SQL_DESC_BIND_TYPE, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_PARAM_OPERATION_PTR:
rc = m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_PARAM_STATUS_PTR:
rc = m_ImpParamDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_PARAMS_PROCESSED_PTR:
rc = m_ImpParamDesc->GetDescField(0, SQL_DESC_ROWS_PROCESSED_PTR, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_PARAMSET_SIZE:
rc = m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_QUERY_TIMEOUT:
retValue.u.u32Value = m_QueryTimeout;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_RETRIEVE_DATA:
retValue.u.u32Value = m_RetrieveData;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_ROW_ARRAY_SIZE:
case SQL_ROWSET_SIZE:
rc = m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_ROW_BIND_OFFSET_PTR:
rc = m_AppRowDesc->GetDescField(0, SQL_DESC_BIND_OFFSET_PTR, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_ROW_BIND_TYPE:
rc = m_AppRowDesc->GetDescField(0, SQL_DESC_BIND_TYPE, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_ROW_NUMBER:
if (m_StmtState == STMT_EXECUTED || m_StmtState == STMT_FETCHED_TO_END)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
rc = m_ImpRowDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, &ArrayStatusPtr,
sizeof(ArrayStatusPtr), NULL);
if (ArrayStatusPtr != NULL)
{
if (ArrayStatusPtr[m_RowNumber] == SQL_ROW_DELETED ||
ArrayStatusPtr[m_RowNumber] == SQL_ROW_ERROR)
{
setDiagRec(DRIVER_ERROR, IDS_HY_109);
return SQL_ERROR;
}
}
#ifdef _WIN64
retValue.u.s64Value = m_RowNumber;
retValue.dataType = SQL_C_UBIGINT;
#else
retValue.u.u32Value = m_RowNumber;
retValue.dataType = SQL_IS_UINTEGER;
#endif
break;
case SQL_ATTR_ROW_OPERATION_PTR:
rc = m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_ROW_STATUS_PTR:
rc = m_ImpRowDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_ROWS_FETCHED_PTR:
rc = m_ImpRowDesc->GetDescField(0, SQL_DESC_ROWS_PROCESSED_PTR, ValuePtr, BufferLength,
StringLengthPtr);
DescAttr = TRUE;
break;
case SQL_ATTR_SIMULATE_CURSOR:
retValue.u.u32Value = m_SimulateCursor;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_USE_BOOKMARKS:
retValue.u.u32Value = m_UseBookmarks;
retValue.dataType = SQL_IS_UINTEGER;
break;
case SQL_ATTR_FETCH_BUFFER_SIZE:
retValue.u.u32Value = m_FetchBufferSize/1024;
retValue.dataType = SQL_IS_INTEGER;
break;
case SQL_ATTR_ROWCOUNT64_PTR:
retValue.u.s64Value = m_RowCount;
retValue.dataType = SQL_C_SBIGINT;
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_092);
rc = SQL_ERROR;
break;
}
if (rc == SQL_SUCCESS && (!DescAttr))
rc = returnAttrValue(TRUE, this, &retValue, ValuePtr, BufferLength, StringLengthPtr);
return rc;
}
SQLRETURN CStmt::BindCol(SQLUSMALLINT ColumnNumber,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN *StrLen_or_IndPtr)
{
CDesc *pDesc;
unsigned long retCode;
clearError();
m_CurrentOdbcAPI = SQL_API_SQLBINDCOL;
pDesc = m_AppRowDesc;
if (pDesc == SQL_NULL_HDESC)
{
setDiagRec(DRIVER_ERROR, IDS_HY_000, 0, "ARD is NULL");
return SQL_ERROR;
}
if (ColumnNumber == 0)
{
setDiagRec(DRIVER_ERROR, IDS_07_009);
return SQL_ERROR;
}
retCode = pDesc->BindCol(ColumnNumber,TargetType, TargetValuePtr, BufferLength, StrLen_or_IndPtr);
if (retCode != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
return SQL_ERROR;
}
return SQL_SUCCESS;
}
SQLRETURN CStmt::BindParameter(SQLUSMALLINT ParameterNumber,
SQLSMALLINT InputOutputType,
SQLSMALLINT ValueType,
SQLSMALLINT ParameterType,
SQLULEN ColumnSize,
SQLSMALLINT DecimalDigits,
SQLPOINTER ParameterValuePtr,
SQLLEN BufferLength,
SQLLEN *StrLen_or_IndPtr)
{
CDesc *pDesc;
unsigned long retCode;
// SQLINTEGER ODBCAppVersion;
clearError();
m_CurrentOdbcAPI = SQL_API_SQLBINDPARAMETER;
pDesc = m_AppParamDesc;
if (pDesc == SQL_NULL_HDESC)
{
setDiagRec(DRIVER_ERROR, IDS_HY_000, 0, "APD is NULL");
return SQL_ERROR;
}
// ODBCAppVersion = getODBCAppVersion();
// if(ValueType==SQL_C_DEFAULT)
// if ((retCode = getCDefault(ParameterType, ODBCAppVersion, ValueType)) != SQL_SUCCESS)
// return retCode;
retCode = pDesc->BindParameter(ParameterNumber,
InputOutputType, ValueType, ParameterValuePtr, BufferLength, StrLen_or_IndPtr);
if (retCode != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
return SQL_ERROR;
}
pDesc = m_ImpParamDesc;
if (pDesc == SQL_NULL_HDESC)
{
setDiagRec(DRIVER_ERROR, IDS_HY_000, 0, "IPD is NULL");
return SQL_ERROR;
}
retCode = pDesc->BindParameter(ParameterNumber, ParameterType, ColumnSize, DecimalDigits);
if (retCode != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
return SQL_ERROR;
}
return SQL_SUCCESS;
}
SQLRETURN CStmt::SendSQLCommand(BOOL SkipProcess, SQLCHAR *StatementText,
SQLINTEGER TextLength)
{
char tempStr[2048];
char *token;
char *delimiters = " {(\t\r\n";
unsigned char* sqlString;
unsigned long sqlStringLen;
unsigned long len;
SQLINTEGER translen=0;
SQLULEN MaxRowsetSize;
SQLULEN AppArrayStatusSize;
BYTE *inputParams = 0;
BYTE *outputColumns = 0;
SQLRETURN rc;
setStmtLabel(m_StmtLabelOrg); // need to revert it back to original because of catalog API
if (m_ConnectHandle->getConnectionStatus() == SQL_CD_TRUE)
{
clearError();
setDiagRec(DRIVER_ERROR, IDS_08_S01, -20005);
return SQL_ERROR;
}
if (! SkipProcess)
{
clearError();
setDiagRowCount(-1, -1);
InitParamColumnList();
if (m_StmtState == STMT_EXECUTED)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
if (TextLength == SQL_NTS)
sqlStringLen = strlen((const char *)StatementText);
else
sqlStringLen = TextLength;
sqlString = new BYTE[sqlStringLen + 1];
if (sqlString == 0)
{
setDiagRec(DRIVER_ERROR, IDS_HY_001);
return SQL_ERROR;
}
if (m_intStmtType != TYPE_QS)
trimSqlString(StatementText, sqlString, sqlStringLen);
else
{
strcpy((char*)sqlString, (char*)StatementText);
wmstrim((char*)sqlString);
}
// if (sqlStringLen == 0 || sqlStringLen > USHRT_MAX)
if (sqlStringLen <= 0 )
{
setDiagRec(DRIVER_ERROR, IDS_S1_090);
delete[] sqlString;
return SQL_ERROR;
}
if(pdwGlobalTraceVariable && *pdwGlobalTraceVariable)
TraceOut(TR_ODBC_API, "CStmt::SendSQLCommand sqlString \"%s\", sqlStringLen %d",
sqlString, sqlStringLen);
// sqlString is already in UTF8
m_SqlString.assign((const char *)sqlString, sqlStringLen);
if (sqlStringLen < sizeof(tempStr))
len = sqlStringLen;
else
len = sizeof(tempStr)-1;
strcpyUTF8(tempStr, (const char *)m_SqlString.c_str(), sizeof(tempStr), len);
token = strtok(tempStr, delimiters);
if (token == NULL)
{
setDiagRec(DRIVER_ERROR, IDS_S1_009);
delete sqlString;
return SQL_ERROR;
}
/* Vijay - Changes not to block statements of type SELECT
if ((strcmp(token, "SELECT") == 0) || (strcmp(token, "SEL") == 0)
|| (strcmp(token, "LOCK") == 0) || (strcmp(token, "LOCKING") == 0)
|| (strcmp(token, "INVOKE") == 0) || (strcmp(token, "EXPLAIN") == 0)
|| (strcmp(token, "SHOWCONTROL") == 0) || (strcmp(token, "SHOWDDL") == 0)
|| (strcmp(token, "SHOWSHAPE") == 0) || (strcmp(token, "SHOWPLAN") == 0)
|| (strcmp(token, "SHOWLABEL") == 0) || (strcmp(token, "MAINTAIN") == 0)
|| (strcmp(token, "REORG") == 0) || (strcmp(token, "REORGANIZE") == 0)
|| (strcmp(token, "PURGEDATA") == 0)) // JoyJ - Added for PURGEDATA
m_StmtType = TYPE_SELECT;
*/
if (_strnicmp(token, "WMSOPEN", 7) == 0)
{
m_intStmtType = TYPE_QS;
m_StmtType = TYPE_QS_OPEN;
}
else if (_strnicmp(token, "WMSCLOSE", 8) == 0)
{
m_intStmtType = TYPE_UNKNOWN;
m_StmtType = TYPE_QS_CLOSE;
}
else if (m_intStmtType == TYPE_QS)
{
if (_strnicmp(token, "STATUS", 6) == 0)
m_StmtType = TYPE_SELECT;
else if (_strnicmp(token, "CANCEL", 6) == 0)
m_StmtType = TYPE_UNKNOWN;
else if (_strnicmp(token, "SUSPEND", 7) == 0)
m_StmtType = TYPE_UNKNOWN;
else if (_strnicmp(token, "RESUME", 6) == 0)
m_StmtType = TYPE_UNKNOWN;
else if (_strnicmp(token, "ALTPRI", 6) == 0)
m_StmtType = TYPE_UNKNOWN;
else if (_strnicmp(token, "ADD", 3) == 0)
m_StmtType = TYPE_UNKNOWN;
else if (_strnicmp(token, "ALTER", 5) == 0)
m_StmtType = TYPE_UNKNOWN;
else if (_strnicmp(token, "DELETE", 6) == 0)
m_StmtType = TYPE_UNKNOWN;
else if (_strnicmp(token, "INFO", 4) == 0)
m_StmtType = TYPE_SELECT;
else
m_StmtType = TYPE_UNKNOWN;
}
else if (_strnicmp(token, "CMDOPEN", 7) == 0)
{
m_intStmtType = TYPE_CMD;
m_StmtType = TYPE_CMD_OPEN;
}
else if (_strnicmp(token, "CMDCLOSE", 8) == 0)
{
m_intStmtType = TYPE_UNKNOWN;
m_StmtType = TYPE_CMD_CLOSE;
}
else if (m_intStmtType == TYPE_CMD)
{
if ((_strnicmp(token, "LIST", 4) == 0) ||
(_strnicmp(token, "STATUS", 6) == 0) ||
(_strnicmp(token, "INFO", 4) == 0))
m_StmtType = TYPE_SELECT;
else if ((_strnicmp(token, "ADD", 3) == 0) ||
(_strnicmp(token, "ALTER", 5) == 0))
m_StmtType = TYPE_INSERT;
else if (_strnicmp(token, "DELETE", 6) == 0)
m_StmtType = TYPE_DELETE;
else if ((_strnicmp(token, "START", 5) == 0) ||
(_strnicmp(token, "STOP", 4) == 0))
m_StmtType = TYPE_DELETE;
}
else if (strcmp(token, "SELECT") == 0)
m_StmtType = TYPE_SELECT;
else if ((strcmp(token, "INSERT") == 0) || (strcmp(token, "INS") == 0) ||
(strcmp(token, "UPSERT") == 0)) // Add for "UPSERT" support
m_StmtType = TYPE_INSERT;
else if ((strcmp(token, "UPDATE") == 0) || (strcmp(token, "MERGE") == 0))
m_StmtType = TYPE_UPDATE;
else if ((strcmp(token, "DELETE") == 0))
m_StmtType = TYPE_DELETE;
else if (strcmp(token, "SMD") == 0) // added for user module support
m_StmtType = TYPE_SMD;
else if ((strcmp(token, "CALL") == 0) || (strcmp(token, "?=CALL") == 0)) // added for stored proc call support
m_StmtType = TYPE_CALL;
else if (_strnicmp(token, "INFOSTATS", 9) == 0)
m_StmtType = TYPE_STATS;
else if (strcmp(token, "?=") == 0)
{
token = strtok(NULL, delimiters);
if (token == NULL)
{
setDiagRec(DRIVER_ERROR, IDS_S1_009);
delete sqlString;
return SQL_ERROR;
}
if (strcmp(token, "CALL") == 0)
m_StmtType = TYPE_CALL;
else
m_StmtType = TYPE_UNKNOWN;
}
else if (strcmp(token, "?") == 0)
{
token = strtok(NULL, delimiters);
if (token == NULL)
{
setDiagRec(DRIVER_ERROR, IDS_S1_009);
delete sqlString;
return SQL_ERROR;
}
if ((strcmp(token, "=") == 0) && (strcmp(strtok(NULL, delimiters), "CALL") == 0))
m_StmtType = TYPE_CALL;
else
m_StmtType = TYPE_UNKNOWN;
}
else if (_strnicmp(token, "LOBUPDATE", 9) == 0)
{
if (m_SrvrCallContext.u.extractLobParams.lobHandle == NULL)
{
return SQL_ERROR;
}
m_CurrentOdbcAPI = SRVR_API_UPDATELOB;
return SQL_NEED_DATA;
}
else
{
/*
// In case we decide to support "SET CATALOG and SET SCHEMA" through EXECUTE, Strongly this
// should not be allowed.
if (strcmp(token, "SET") == 0)
{
char settempStr[300];
char *settoken;
char *setdelimiters = ".\n";
char catTempStr[128+1];
char schTempStr[128+1];
catTempStr[0] = '\0';
schTempStr[0] = '\0';
if (sqlStringLen < sizeof(settempStr))
len = sqlStringLen;
else
len = sizeof(settempStr)-1;
token = strtok(NULL, delimiters);
if (strcmp(token, "CATALOG") == 0)
{
token = strtok(NULL, delimiters);
strncpy(settempStr, (const char *)m_SqlString.c_str() + (token-(const char *)m_SqlString.c_str()), len);
settempStr[len] = '\0';
settoken = strtok(settempStr, setdelimiters); // ignore first token
if (settoken != NULL)
// Do catalog change here
}
else if (strcmp(token, "SCHEMA") == 0)
{
token = strtok(NULL, delimiters);
strncpy(settempStr, (const char *)m_SqlString.c_str() + (token-(const char *)m_SqlString.c_str()), len);
settempStr[len] = '\0';
settoken = strtok(settempStr, setdelimiters); // ignore first token
if (settoken != NULL)
{
strcpy(schTempStr,settoken);
settoken = strtok(NULL, setdelimiters);
if (settoken != NULL)
{
strcpy(catTempStr,schTempStr);
strcpy(schTempStr,settoken);
}
if (catTempStr[0] != '\0')
// Do catalog change here
if (schTempStr[0] != '\0')
// Do schema change here
}
}
}
*/
m_StmtType = TYPE_UNKNOWN;
}
// Need to check if SQL_ATTR_CONCURRENCY attribute is set to SQL_CONCUR_READ_ONLY then return error if
// WHERE CURRENT OF is used in UPDATE or DELETE statements. The reason is if SQL_CONCUR_READ_ONLY is set
// and SQL_ATTR_FETCH_BUFFER_SIZE is more than ZERO OR m_RowsFetched returned by server is greater than
// ONE which is used to do bulk fetches then we may go head and update or delete a ROW which is not
// the ROW application wants to update or delete. Inspite of SQL_CONCUR_READ_ONLY
// is set SQL/MX allows to update or delete since FOR UPDATE OF syntax in SELECT statement takes higher
// priority. If SQL_ATTR_CONCURRENCY attribute is NOT set to SQL_CONCUR_READ_ONLY then we only do one ROW
// at a time then we are OK in update or delete.
if (m_StmtType == TYPE_UPDATE || m_StmtType == TYPE_DELETE)
{
// Last FOUR tokens in ANSI SQL syntax for positioned update/delete are
// always "WHERE", "CURRENT", "OF", "{cursor name | ext_cursor-name | iterator-name}".
char whereCurrectof[] = "WHERE CURRENT OF";
char *pwhereCurrentof;
int rwhereCurrentof = 0;
sqlString[0] = '\0';
if (TextLength == SQL_NTS)
sqlStringLen = strlen((const char *)StatementText);
else
sqlStringLen = TextLength;
if (m_intStmtType != TYPE_QS)
trimSqlString(StatementText, sqlString, sqlStringLen, TRUE);
else
{
strcpy((char*)sqlString, (char*)StatementText);
wmstrim((char*)sqlString);
}
pwhereCurrentof = strstr((char *)sqlString, whereCurrectof);
if (pwhereCurrentof != NULL)
{
char tCursor[MAX_CURSOR_NAME_LEN+1];
SQLUINTEGER tConcurrency = -1;
SQLUINTEGER tRowsFetched = -1;
rwhereCurrentof = (int) (pwhereCurrentof - (char *)sqlString + 17); // 17 = 16 (len of WHERE CURRENT OF) + 1 (space)
sqlString[0] = '\0';
tCursor[0] = '\0';
if (TextLength == SQL_NTS)
sqlStringLen = strlen((const char *)StatementText);
else
sqlStringLen = TextLength;
if (m_intStmtType != TYPE_QS)
trimSqlString(StatementText, sqlString, sqlStringLen);
else
{
strcpy((char*)sqlString, (char*)StatementText);
wmstrim((char*)sqlString);
}
strcpyUTF8(tCursor, (char *)sqlString + rwhereCurrentof, sizeof(tCursor), sqlStringLen - rwhereCurrentof);
if (tCursor != NULL)
{
CHANDLECOLLECT::iterator itr;
for (itr = m_ConnectHandle->m_StmtCollect.begin() ; itr != m_ConnectHandle->m_StmtCollect.end() ; ++itr)
{
if(strcmp(tCursor, ((CStmt *)(*itr))->m_CursorName) == 0)
{
tConcurrency = ((CStmt *)(*itr))->m_Concurrency;
tRowsFetched = ((CStmt *)(*itr))->m_RowsFetched;
break;
}
}
if (tConcurrency != -1)
{
if (tConcurrency == SQL_CONCUR_READ_ONLY)
{
setDiagRec(DRIVER_ERROR, IDS_HY_000, 0, "Cursor is Read-only. No updates are allowed. To update set Statement attribute SQL_ATTR_CONCURRENCY to SQL_CONCUR_LOCK for SELECT statement handle.");
delete sqlString;
return SQL_ERROR;
}
if (tRowsFetched > 1)
{
setDiagRec(DRIVER_ERROR, IDS_HY_000, 0, "Maximum rows fetched greater than ONE. To update set Statement attribute SQL_ATTR_MAX_ROWS to 1 for SELECT statement handle.");
delete sqlString;
return SQL_ERROR;
}
}
}
}
}
delete sqlString;
MaxRowsetSize = 0;
if (m_intStmtType != TYPE_QS && checkInputParam(m_SqlString))
{
#ifdef _WIN64
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &MaxRowsetSize, SQL_C_UBIGINT, NULL);
#else
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &MaxRowsetSize, SQL_IS_UINTEGER, NULL);
#endif
if (m_StmtType == TYPE_INSERT)
{
m_StmtType = TYPE_INSERT_PARAM;
}
if (m_CurrentOdbcAPI == SQL_API_SQLEXECDIRECT)
m_SrvrCallContext.odbcAPI = SQL_API_SQLPREPARE;
else
m_SrvrCallContext.odbcAPI = m_CurrentOdbcAPI;
}
else
m_SrvrCallContext.odbcAPI = m_CurrentOdbcAPI;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.connectionTimeout = m_ConnectHandle->getConnectionTimeout();
m_SrvrCallContext.u.sendSQLcommandParams.queryTimeout = m_QueryTimeout;
m_SrvrCallContext.u.sendSQLcommandParams.sqlString = m_SqlString.c_str();
m_SrvrCallContext.u.sendSQLcommandParams.stmtLabel = m_StmtLabel;
m_SrvrCallContext.u.sendSQLcommandParams.stmtName = m_StmtName;
m_SrvrCallContext.u.sendSQLcommandParams.cursorName = m_CursorName;
m_SrvrCallContext.u.sendSQLcommandParams.moduleName = NULL;
m_SrvrCallContext.u.sendSQLcommandParams.sqlStmtType = m_StmtType;
m_SrvrCallContext.u.sendSQLcommandParams.asyncEnable = m_AsyncEnable;
m_SrvrCallContext.u.sendSQLcommandParams.holdableCursor = m_CursorHoldable;
m_SrvrCallContext.maxRowsetSize = MaxRowsetSize;
}
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if ((m_AsyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendPrepare - _beginthreadex()");
rc = SQL_ERROR;
}
ResumeThread(m_AsyncThread);
rc = SQL_STILL_EXECUTING;
Sleep(0);
}
else
{
if ((m_SyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendPrepare - _beginthreadex()");
rc = SQL_ERROR;
}
else
{
ResumeThread(m_SyncThread);
WaitForSingleObject(m_SyncThread,INFINITE);
GetExitCodeThread(m_SyncThread, &m_ThreadStatus);
rc = m_ThreadStatus;
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
// rc = ThreadControlProc(&m_SrvrCallContext);
if (m_CurrentOdbcAPI == SQL_API_SQLEXECDIRECT && m_SrvrCallContext.odbcAPI == SQL_API_SQLPREPARE)
{
if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
rc = SendExecute(FALSE);
else if (m_StmtType == TYPE_INSERT_PARAM)
{
#ifdef _WIN64
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &AppArrayStatusSize, SQL_C_UBIGINT, NULL);
#else
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &AppArrayStatusSize, SQL_IS_UINTEGER, NULL);
#endif
m_ImpParamDesc->setDescArrayStatus(AppArrayStatusSize,SQL_PARAM_ERROR);
}
}
}
}
if (rc != SQL_SUCCESS && ((m_StmtType == TYPE_QS_OPEN) || (m_StmtType == TYPE_CMD_OPEN))) m_intStmtType = TYPE_UNKNOWN;
return rc;
}
SQLRETURN CStmt::Prepare(SQLCHAR *StatementText,
SQLINTEGER TextLength)
{
SQLRETURN rc;
BOOL SkipProcess = FALSE;
m_CurrentOdbcAPI = SQL_API_SQLPREPARE;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
rc = m_ThreadStatus;
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "SQLPrepare - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
SkipProcess = TRUE;
rc = SendSQLCommand(SkipProcess, StatementText, TextLength);
}
}
else
rc = SendSQLCommand(SkipProcess, StatementText, TextLength);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
if (m_StmtType == TYPE_SELECT)
m_StmtState = STMT_PREPARED;
else
m_StmtState = STMT_PREPARED_NO_RESULT;
m_StmtPrepared = TRUE;
setRowCount(-1);
m_isClosed = false;
break;
case SQL_STILL_EXECUTING:
m_StmtState = STMT_STILL_EXECUTING;
break;
case SQL_ERROR:
if (m_AsyncCanceled == TRUE)
{
m_AsyncCanceled = FALSE;
setDiagRec(DRIVER_ERROR, IDS_S1_008);
}
m_StmtState = STMT_ALLOCATED;
setRowCount(-1);
break;
case SQL_NEED_DATA:
case SQL_NO_DATA:
case SQL_INVALID_HANDLE:
default:
break;
}
return rc;
}
SQLRETURN CStmt::ExecDirect(SQLCHAR *StatementText,
SQLINTEGER TextLength)
{
SQLRETURN rc;
BOOL SkipProcess = FALSE;
m_CurrentOdbcAPI = SQL_API_SQLEXECDIRECT;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
{
if (m_ThreadStatus == SQL_SUCCESS || m_ThreadStatus == SQL_SUCCESS_WITH_INFO)
{
if (m_SrvrCallContext.odbcAPI == SQL_API_SQLPREPARE)
rc = SendExecute(FALSE);
}
rc = m_ThreadStatus;
}
}
//return rc;
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "SQLPrepare - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
{
if (m_SrvrCallContext.odbcAPI == SQL_API_SQLPREPARE)
rc = SendSQLCommand(TRUE, StatementText, TextLength);
else
rc = SendExecute(TRUE);
}
else
rc = SendSQLCommand(FALSE, StatementText, TextLength);
}
}
else
rc = SendSQLCommand(FALSE, StatementText, TextLength);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
// If it is SQLExecute or SQLExecDirect, then SQLExecDirect is done
if (m_SrvrCallContext.odbcAPI != SQL_API_SQLPREPARE)
{
if (m_StmtType == TYPE_SELECT || m_StmtType == TYPE_STATS || m_StmtType == TYPE_CALL) // added for INFOSTATS support
m_StmtState = STMT_EXECUTED;
else
m_StmtState = STMT_EXECUTED_NO_RESULT;
}
m_StmtPrepared = FALSE;
m_isClosed = false;
if (m_StmtQueryType == SQL_SELECT_UNIQUE && m_RowCount == 0)
m_StmtState = STMT_EXECUTED_NO_RESULT;
break;
case SQL_STILL_EXECUTING:
m_StmtState = STMT_STILL_EXECUTING;
break;
case SQL_NEED_DATA:
m_StmtState = STMT_PARAM_DATA_NOT_CALLED;
break;
case SQL_ERROR:
if (m_AsyncCanceled)
{
m_AsyncCanceled = FALSE;
setDiagRec(DRIVER_ERROR, IDS_S1_008);
}
if (m_StmtState != STMT_EXECUTED)
m_StmtState = STMT_ALLOCATED;
setRowCount(-1);
break;
case SQL_NO_DATA:
if (m_StmtQueryType == SQL_SELECT_UNIQUE)
{
m_StmtState = STMT_EXECUTED_NO_RESULT;
rc = SQL_SUCCESS;
}
case SQL_INVALID_HANDLE:
default:
break;
}
return rc;
}
SQLRETURN CStmt::setDescRec(const SQLItemDescList_def *IPDDescList, const SQLItemDescList_def *IRDDescList)
{
CDesc *pDesc;
unsigned long retCode = SQL_SUCCESS;
unsigned long retCode1;
if (IPDDescList != NULL)
{
pDesc = m_ImpParamDesc;
if (pDesc != SQL_NULL_HDESC)
{
retCode = pDesc->setDescRec(IPDDescList);
if (retCode != SQL_SUCCESS)
setDiagRec(DRIVER_ERROR, retCode);
}
m_NumParams = IPDDescList->_length;
}
else
m_NumParams = 0;
if (IRDDescList != NULL)
{
pDesc = m_ImpRowDesc;
if (pDesc != SQL_NULL_HDESC)
{
retCode1 = pDesc->setDescRec(IRDDescList);
if (retCode1 != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode1);
retCode = retCode1;
}
}
m_NumResultCols = IRDDescList->_length;
}
else
m_NumResultCols = 0;
// Reset the FetchRelated members,
m_ResultsetRowsFetched = 0;
m_RowsFetched = -1;
m_CurrentRowFetched = 0;
m_CurrentRowInRowset = 0;
m_RowsetSize = 0;
m_RowNumber = 0;
return retCode;
}
SQLRETURN CStmt::setStmtData(BYTE *&inputParams, BYTE *&outputColumns)
{
unsigned long retCode = SQL_SUCCESS;
long tmpLen = 0;
if (inputParams != NULL)
{
tmpLen = *(long *)(inputParams);
if ((m_InputParams = new BYTE[tmpLen]) == NULL)
{
m_InputParams = 0;
return false;
}
else
memcpy(m_InputParams, inputParams, tmpLen);
}
else
m_InputParams = 0;
if (outputColumns != NULL)
{
tmpLen = *(long *)(outputColumns);
if ((m_OutputColumns = new BYTE[tmpLen]) == NULL)
{
m_OutputColumns = 0;
return false;
}
else
memcpy(m_OutputColumns, outputColumns, tmpLen);
}
else
m_OutputColumns = 0;
return retCode;
}
SQLRETURN CStmt::getDescRec(short odbcAPI,
SQLUSMALLINT ColumnNumber,
SQLWCHAR *ColumnName,
SQLSMALLINT BufferLength,
SQLSMALLINT *NameLengthPtr,
SQLSMALLINT *DataTypePtr,
SQLULEN *ColumnSizePtr,
SQLSMALLINT *DecimalDigitsPtr,
SQLSMALLINT *NullablePtr)
{
CDesc *pDesc;
unsigned long retCode;
SQLRETURN rc = SQL_SUCCESS;
UCHAR errorMsg[MAX_TRANSLATE_ERROR_MSG_LEN];
clearError();
m_CurrentOdbcAPI = odbcAPI;
if (ColumnNumber == 0)
{
setDiagRec(DRIVER_ERROR, IDS_07_009);
return SQL_ERROR;
}
switch (odbcAPI)
{
case SQL_API_SQLDESCRIBECOL:
if ((m_StmtState == STMT_EXECUTED_NO_RESULT) &&
(m_StmtQueryType != SQL_SELECT_UNIQUE))
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
if (m_StmtState == STMT_PREPARED_NO_RESULT)
{
setDiagRec(DRIVER_ERROR, IDS_07_005);
return SQL_ERROR;
}
pDesc = m_ImpRowDesc;
break;
case SQL_API_SQLDESCRIBEPARAM :
pDesc = m_ImpParamDesc;
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_000);
return SQL_ERROR;
}
retCode = pDesc->getDescRec(ColumnNumber, ColumnName, BufferLength, NameLengthPtr,
DataTypePtr, ColumnSizePtr, DecimalDigitsPtr, NullablePtr, errorMsg, sizeof(errorMsg));
if (retCode != SQL_SUCCESS)
{
if (errorMsg[0] != '\0')
setDiagRec(DRIVER_ERROR, retCode, 0, (char *)errorMsg);
else
setDiagRec(DRIVER_ERROR, retCode);
switch (retCode)
{
case IDS_01_004:
case IDS_186_DSTODRV_TRUNC:
rc = SQL_SUCCESS_WITH_INFO;
break;
default:
rc = SQL_ERROR;
break;
}
}
return rc;
}
void CStmt::getStmtData(BYTE *&inputParams, BYTE *&outputColumns)
{
inputParams = m_InputParams;
outputColumns = m_OutputColumns;
}
SQLRETURN CStmt::getDescSize(short odbcAPI, SQLSMALLINT *CountPtr)
{
SQLRETURN rc = SQL_SUCCESS;
clearError();
m_CurrentOdbcAPI = odbcAPI;
switch (odbcAPI)
{
case SQL_API_SQLNUMRESULTCOLS:
if (CountPtr != NULL)
*CountPtr = m_NumResultCols;
break;
case SQL_API_SQLNUMPARAMS:
if (CountPtr != NULL)
*CountPtr = m_NumParams;
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_000);
return SQL_ERROR;
}
return rc;
}
SQLRETURN CStmt::FreeStmt(short odbcAPI, SQLUSMALLINT Option)
{
CDesc *pDesc;
SQLRETURN rc = SQL_SUCCESS;
clearError();
m_CurrentOdbcAPI = odbcAPI;
if (odbcAPI == SQL_API_SQLCLOSECURSOR || Option == SQL_CLOSE || Option == SQL_DROP)
setRowCount(-1);
switch (Option)
{
case SQL_UNBIND:
pDesc = m_AppRowDesc;
if (pDesc != NULL)
pDesc->clear();
break;
case SQL_RESET_PARAMS:
pDesc = m_AppParamDesc;
if (pDesc != NULL)
pDesc->clear();
InitInputValueList();
break;
case SQL_CLOSE:
switch (odbcAPI)
{
case SQL_API_SQLFREESTMT:
switch (m_StmtState)
{
case STMT_ALLOCATED:
case STMT_PREPARED:
case STMT_PREPARED_NO_RESULT:
case STMT_EXECUTED_NO_RESULT:
if(m_spjNumResultSets > 0)
{
m_spjNumResultSets = 0;
m_spjCurrentResultSetIndex = 0;
delete[] m_spjResultSets;
m_spjResultSets = NULL;
}
return SQL_SUCCESS;
default:
break;
}
break;
case SQL_API_SQLCLOSECURSOR:
switch (m_StmtState)
{
case STMT_ALLOCATED:
case STMT_PREPARED:
case STMT_PREPARED_NO_RESULT:
case STMT_EXECUTED_NO_RESULT:
if(m_spjNumResultSets > 0)
{
m_spjNumResultSets = 0;
m_spjCurrentResultSetIndex = 0;
delete[] m_spjResultSets;
m_spjResultSets = NULL;
}
if(m_StmtQueryType != SQL_SELECT_UNIQUE)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
default:
break;
}
break;
case SQL_API_SQLMORERESULTS:
switch (m_StmtState)
{
case STMT_ALLOCATED:
case STMT_PREPARED:
case STMT_PREPARED_NO_RESULT:
return SQL_NO_DATA;
case STMT_EXECUTED_NO_RESULT:
return SQL_NO_DATA;
case STMT_FETCHED_TO_END:
if((m_spjNumResultSets > 0) && (++m_spjCurrentResultSetIndex < m_spjNumResultSets))
{
setDescRec(&m_spjInputParamDesc, &m_spjResultSets[m_spjCurrentResultSetIndex].spjOutputItemDesc);
return SQL_SUCCESS;
}
else
rc = SQL_NO_DATA;
default:
break;
}
default: // Want to fall thru
break;
}
rc = Close(Option);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
revertStmtState();
rc = SQL_SUCCESS;
break;
case SQL_ERROR:
case SQL_STILL_EXECUTING:
case SQL_NEED_DATA:
case SQL_NO_DATA:
case SQL_INVALID_HANDLE:
default:
break;
}
if (odbcAPI == SQL_API_SQLMORERESULTS)
rc = SQL_NO_DATA;
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_092);
rc = SQL_ERROR;
}
return rc;
}
SQLRETURN CStmt::SendGetSQLCatalogsArgsHlpr(bool WCharArg, SQLCHAR* arg, int argLen, char * dest, int destLen, SQLUINTEGER metaDataId)
{
SQLRETURN rc = SQL_SUCCESS;
int translen = 0;
char transError[128];
BOOL isCase = FALSE;
if(argLen > 0)
{
if (!WCharArg) // DriverLocale to UTF8 translation here
{
if ((arg[0] == '"') && (arg[argLen-1] == '"'))
isCase = TRUE;
if (TranslateUTF8(FALSE, (char*)arg, argLen, dest, destLen, &translen, transError) != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, IDS_193_DRVTODS_ERROR, 0, transError);
return SQL_ERROR;
}
}
else //WChar
{
if (*(wchar_t *)arg == L'"' && *((wchar_t *)arg + (argLen/2)-1) == L'"')
isCase = TRUE;
if(WCharToUTF8((wchar_t *)arg, argLen/2, dest, destLen, &translen, transError) != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, IDS_193_DRVTODS_ERROR, 0, transError);
return SQL_ERROR;
}
}
}
else if(dest != NULL)
*dest = '\0';
if(!isCase && metaDataId)
_strupr(dest);
return rc;
}
SQLRETURN CStmt::SendGetSQLCatalogs(short odbcAPI,
BOOL SkipProcess,
SQLWCHAR *CatalogNameW,
SQLSMALLINT NameLength1,
SQLWCHAR *SchemaNameW,
SQLSMALLINT NameLength2,
SQLWCHAR *TableNameW,
SQLSMALLINT NameLength3,
SQLWCHAR *ColumnNameW,
SQLSMALLINT NameLength4,
SQLWCHAR *TableTypeW,
SQLSMALLINT NameLength5,
SQLUSMALLINT IdentifierType,
SQLUSMALLINT Scope,
SQLUSMALLINT Nullable,
SQLSMALLINT SqlType,
SQLUSMALLINT Unique,
SQLUSMALLINT Reserved,
SQLWCHAR *FKCatalogNameW,
SQLSMALLINT NameLength6,
SQLWCHAR *FKSchemaNameW,
SQLSMALLINT NameLength7,
SQLWCHAR *FKTableNameW,
SQLSMALLINT NameLength8)
{
SQLRETURN rc;
char *cEmpty = "";
char *cAll = 0;
SQLCHAR *substCatalogName;
SQLSMALLINT catalogNameLen;
SQLCHAR *substSchemaName;
SQLSMALLINT schemaNameLen;
SQLCHAR *substTableName;
SQLSMALLINT tableNameLen;
SQLCHAR *substColumnName;
SQLSMALLINT columnNameLen;
SQLCHAR *substTableType;
SQLSMALLINT tableTypeLen;
SQLCHAR *FKsubstCatalogName;
SQLSMALLINT FKcatalogNameLen;
SQLCHAR *FKsubstSchemaName;
SQLSMALLINT FKschemaNameLen;
SQLCHAR *FKsubstTableName;
SQLSMALLINT FKtableNameLen;
bool IsCase = FALSE;
bool isWCharData = false;
if (m_ConnectHandle->getConnectionStatus() == SQL_CD_TRUE)
{
clearError();
setDiagRec(DRIVER_ERROR, IDS_08_S01, -20005);
return SQL_ERROR;
}
if (odbcAPI == SQL_API_SQLGETTYPEINFO)
{
switch (SqlType)
{
case SQL_BIGINT:
// case SQL_BIT:
// case SQL_BINARY:
case SQL_CHAR:
case SQL_WCHAR:
case SQL_DATE:
case SQL_DECIMAL:
case SQL_DOUBLE:
case SQL_FLOAT:
case SQL_INTEGER:
// case SQL_LONGVARBINARY:
case SQL_LONGVARCHAR:
case SQL_WLONGVARCHAR:
case SQL_NUMERIC:
case SQL_REAL:
case SQL_SMALLINT:
case SQL_TINYINT:
case SQL_TIME:
case SQL_TIMESTAMP:
case SQL_TYPE_DATE:
case SQL_TYPE_TIME:
case SQL_TYPE_TIMESTAMP:
// case SQL_VARBINARY:
case SQL_VARCHAR:
case SQL_WVARCHAR:
case SQL_INTERVAL_YEAR:
case SQL_INTERVAL_MONTH:
case SQL_INTERVAL_DAY:
case SQL_INTERVAL_HOUR:
case SQL_INTERVAL_MINUTE:
case SQL_INTERVAL_SECOND:
case SQL_INTERVAL_YEAR_TO_MONTH:
case SQL_INTERVAL_DAY_TO_HOUR:
case SQL_INTERVAL_DAY_TO_MINUTE:
case SQL_INTERVAL_DAY_TO_SECOND:
case SQL_INTERVAL_HOUR_TO_MINUTE:
case SQL_INTERVAL_HOUR_TO_SECOND:
case SQL_INTERVAL_MINUTE_TO_SECOND:
case SQL_ALL_TYPES:
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_004);
return SQL_ERROR;
}
}
if (! SkipProcess)
{
clearError();
setDiagRowCount(-1, -1);
if (m_StmtState == STMT_FETCHED)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
// Passing a null pointer to a search pattern argument does not constrain
// the search for that argument; that is, a null pointer and the search pattern %
// (any characters) are equivalent. However, a zero-length search patternthat is,
// a valid pointer to a string of length zeromatches only the empty string (""). - ODBC Manual
if (CatalogNameW == NULL)
{
//substCatalogName = (SQLCHAR *)SQL_ALL_CATALOGS;
substCatalogName = (SQLCHAR *)getCurrentCatalog();
catalogNameLen = strlen((const char *)substCatalogName);
isWCharData = false;
}
else
{
substCatalogName = (SQLCHAR *)CatalogNameW;
if(NameLength1 == SQL_NTS)
catalogNameLen = wcslen(CatalogNameW) * 2;
else
catalogNameLen = NameLength1 * 2;
isWCharData = true;
}
if (SendGetSQLCatalogsArgsHlpr(isWCharData,
substCatalogName,
catalogNameLen,
m_CatalogName,
sizeof(m_CatalogName), m_MetadataId) != SQL_SUCCESS)
return SQL_ERROR;
if (SchemaNameW == NULL)
{
if(gDrvrGlobal.RestrictSchema)
{
substSchemaName = (SQLCHAR *)getCurrentSchema();
if(gDrvrGlobal.noSchemaInDSN) //but no schema was specified in DSN
substSchemaName = (SQLCHAR *)SQL_ALL_SCHEMAS;
}
else
substSchemaName = (SQLCHAR *)SQL_ALL_SCHEMAS;
schemaNameLen = strlen((const char *)substSchemaName);
isWCharData = false;
}
else
{
substSchemaName = (SQLCHAR *)SchemaNameW;
if(NameLength2 == SQL_NTS)
schemaNameLen = wcslen(SchemaNameW) * 2;
else
schemaNameLen = NameLength2 * 2;
isWCharData = true;
}
if (SendGetSQLCatalogsArgsHlpr(isWCharData,
substSchemaName,
schemaNameLen,
m_SchemaName,
sizeof(m_SchemaName),m_MetadataId) != SQL_SUCCESS)
return SQL_ERROR;
if (TableNameW == NULL)
{
if (odbcAPI != SQL_API_SQLFOREIGNKEYS)
substTableName = (SQLCHAR *)cAll;
else
substTableName = (SQLCHAR *)cEmpty;
if(substTableName != NULL)
tableNameLen = strlen((const char *)substTableName);
else
tableNameLen = 0;
isWCharData = false;
}
else
{
substTableName = (SQLCHAR *)TableNameW;
if(NameLength3 == SQL_NTS)
tableNameLen = wcslen(TableNameW) * 2;
else
tableNameLen = NameLength3 * 2;
isWCharData = true;
}
if (SendGetSQLCatalogsArgsHlpr(isWCharData,
substTableName,
tableNameLen,
m_TableName,
sizeof(m_TableName),m_MetadataId) != SQL_SUCCESS)
return SQL_ERROR;
if (ColumnNameW == NULL)
{
substColumnName = (SQLCHAR *)cAll;
if(substColumnName != NULL)
columnNameLen = strlen((const char *)substColumnName);
else
columnNameLen = 0;
isWCharData = false;
}
else
{
substColumnName = (SQLCHAR *)ColumnNameW;
if(NameLength4 == SQL_NTS)
columnNameLen = wcslen(ColumnNameW) * 2;
else
columnNameLen = NameLength4 * 2;
isWCharData = true;
}
if (SendGetSQLCatalogsArgsHlpr(isWCharData,
substColumnName,
columnNameLen,
m_ColumnName,
sizeof(m_ColumnName),m_MetadataId) != SQL_SUCCESS)
return SQL_ERROR;
if (TableTypeW == NULL)
{
substTableType = (SQLCHAR *)SQL_ALL_TABLE_TYPES;
tableTypeLen = strlen((const char *)substTableType);
isWCharData = false;
}
else
{
substTableType = (SQLCHAR *)TableTypeW;
if(NameLength5 == SQL_NTS)
tableTypeLen = wcslen(TableTypeW) * 2;
else
tableTypeLen = NameLength5 * 2;
isWCharData = true;
}
if (SendGetSQLCatalogsArgsHlpr(isWCharData,
substTableType,
tableTypeLen,
m_TableType,
sizeof(m_TableType),m_MetadataId) != SQL_SUCCESS)
return SQL_ERROR;
// Added to support SQLForeignKeys
if (FKCatalogNameW == NULL)
{
if (isNskVersion())
FKsubstCatalogName = (SQLCHAR *)getCurrentCatalog();
else
FKsubstCatalogName = (SQLCHAR *)SQL_ALL_CATALOGS;
FKcatalogNameLen = strlen((const char *)FKsubstCatalogName);
isWCharData = false;
}
else
{
FKsubstCatalogName = (SQLCHAR *)FKCatalogNameW;
if(NameLength6 == SQL_NTS)
FKcatalogNameLen = wcslen(FKCatalogNameW) * 2;
else
FKcatalogNameLen = NameLength6 * 2;
isWCharData = true;
}
if (SendGetSQLCatalogsArgsHlpr(isWCharData,
FKsubstCatalogName,
FKcatalogNameLen,
m_FKCatalogName,
sizeof(m_FKCatalogName),m_MetadataId)!= SQL_SUCCESS)
return SQL_ERROR;
if (FKSchemaNameW == NULL)
{
if (isNskVersion())
FKsubstSchemaName = (SQLCHAR *)getCurrentSchema();
else
FKsubstSchemaName = (SQLCHAR *)SQL_ALL_SCHEMAS;
FKschemaNameLen = strlen((const char *)FKsubstSchemaName);
isWCharData = false;
}
else
{
FKsubstSchemaName = (SQLCHAR *)FKSchemaNameW;
if(NameLength7 == SQL_NTS)
FKschemaNameLen = wcslen(FKSchemaNameW) * 2;
else
FKschemaNameLen = NameLength7 * 2;
isWCharData = true;
}
if (SendGetSQLCatalogsArgsHlpr(isWCharData,
FKsubstSchemaName,
FKschemaNameLen,
m_FKSchemaName,
sizeof(m_FKSchemaName),m_MetadataId)!= SQL_SUCCESS)
return SQL_ERROR;
if (FKTableNameW == NULL)
{
FKsubstTableName = (SQLCHAR *)cEmpty;
FKtableNameLen = strlen((const char *)FKsubstTableName);
isWCharData = false;
}
else
{
FKsubstTableName = (SQLCHAR *)FKTableNameW;
if(NameLength8 == SQL_NTS)
FKtableNameLen = wcslen(FKTableNameW) * 2;
else
FKtableNameLen = NameLength8 * 2;
isWCharData = true;
}
if (SendGetSQLCatalogsArgsHlpr(isWCharData,
FKsubstTableName,
FKtableNameLen,
m_FKTableName,
sizeof(m_FKTableName),m_MetadataId)!= SQL_SUCCESS)
return SQL_ERROR;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.catalogNm = m_CatalogName;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.schemaNm = m_SchemaName;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.tableNm = m_TableName;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.columnNm = m_ColumnName;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.tableTypeList = m_TableType;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.columnType = IdentifierType;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.rowIdScope = Scope;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.nullable = Nullable;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.uniqueness = Unique;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.accuracy = Reserved;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.fkcatalogNm = m_FKCatalogName;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.fkschemaNm = m_FKSchemaName;
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.fktableNm = m_FKTableName;
#if (ODBCVER < 0x0300)
switch (SqlType)
{
case SQL_TYPE_DATE:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = SQL_DATE;
break;
case SQL_TYPE_TIME:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = SQL_TIME;
break;
case SQL_TYPE_TIMESTAMP:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = SQL_TIMESTAMP;
break;
case SQL_INTERVAL_YEAR:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -80;
break;
case SQL_INTERVAL_MONTH:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -81;
break;
case SQL_INTERVAL_YEAR_TO_MONTH:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -82;
break;
case SQL_INTERVAL_DAY:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -83;
break;
case SQL_INTERVAL_HOUR:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -84;
break;
case SQL_INTERVAL_MINUTE:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -85;
break;
case SQL_INTERVAL_SECOND:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -86;
break;
case SQL_INTERVAL_DAY_TO_HOUR:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -87;
break;
case SQL_INTERVAL_DAY_TO_MINUTE:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -88;
break;
case SQL_INTERVAL_DAY_TO_SECOND:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -89;
break;
case SQL_INTERVAL_HOUR_TO_MINUTE:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -90;
break;
case SQL_INTERVAL_HOUR_TO_SECOND:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -91;
break;
case SQL_INTERVAL_MINUTE_TO_SECOND:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = -92;
break;
default:
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = SqlType;
break;
}
#else
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.sqlType = SqlType;
#endif
m_SrvrCallContext.u.getSQLCatalogsParams.catalogAPIParams.metadataId = m_MetadataId;
m_SrvrCallContext.u.getSQLCatalogsParams.stmtLabel = m_StmtLabel;
m_SrvrCallContext.odbcAPI = odbcAPI;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.connectionTimeout = m_ConnectHandle->getConnectionTimeout();
m_SrvrCallContext.statementTimeout = m_QueryTimeout;
m_StmtType = TYPE_SELECT; // Since catalog APIs produce result set
}
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if ((m_AsyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendGetSQLCatalogs - _beginthreadex()");
rc = SQL_ERROR;
}
ResumeThread(m_AsyncThread);
rc = SQL_STILL_EXECUTING;
Sleep(0);
}
else
{
if ((m_SyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendPrepare - _beginthreadex()");
rc = SQL_ERROR;
}
else
{
ResumeThread(m_SyncThread);
WaitForSingleObject(m_SyncThread,INFINITE);
GetExitCodeThread(m_SyncThread, &m_ThreadStatus);
rc = m_ThreadStatus;
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
}
// rc = ThreadControlProc(&m_SrvrCallContext);
}
return rc;
}
SQLRETURN CStmt::GetSQLCatalogs(short odbcAPI,
SQLWCHAR *CatalogNameW,
SQLSMALLINT NameLength1,
SQLWCHAR *SchemaNameW,
SQLSMALLINT NameLength2,
SQLWCHAR *TableNameW,
SQLSMALLINT NameLength3,
SQLWCHAR *ColumnNameW,
SQLSMALLINT NameLength4,
SQLWCHAR *TableTypeW,
SQLSMALLINT NameLength5,
SQLUSMALLINT IdentifierType,
SQLUSMALLINT Scope,
SQLUSMALLINT Nullable,
SQLSMALLINT SqlType,
SQLUSMALLINT Unique,
SQLUSMALLINT Reserved,
SQLWCHAR *FKCatalogNameW,
SQLSMALLINT NameLength6,
SQLWCHAR *FKSchemaNameW,
SQLSMALLINT NameLength7,
SQLWCHAR *FKTableNameW,
SQLSMALLINT NameLength8)
{
SQLRETURN rc;
BOOL SkipProcess = FALSE;
m_CurrentOdbcAPI = odbcAPI;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
rc = m_ThreadStatus;
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "GetSQLCatalogs - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
SkipProcess = TRUE;
rc = SendGetSQLCatalogs(odbcAPI, SkipProcess, CatalogNameW, NameLength1, SchemaNameW,
NameLength2, TableNameW, NameLength3, ColumnNameW, NameLength4,
TableTypeW, NameLength5, IdentifierType, Scope, Nullable, SqlType, Unique, Reserved,
FKCatalogNameW, NameLength6, FKSchemaNameW, NameLength7, FKTableNameW, NameLength8);
}
}
else
rc = SendGetSQLCatalogs(odbcAPI, SkipProcess, CatalogNameW, NameLength1, SchemaNameW,
NameLength2, TableNameW, NameLength3, ColumnNameW, NameLength4,
TableTypeW, NameLength5, IdentifierType, Scope, Nullable, SqlType, Unique, Reserved,
FKCatalogNameW, NameLength6, FKSchemaNameW, NameLength7, FKTableNameW, NameLength8);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
m_StmtState = STMT_EXECUTED;
m_isClosed = false;
break;
case SQL_STILL_EXECUTING:
m_StmtState = STMT_STILL_EXECUTING;
break;
case SQL_ERROR:
if (m_AsyncCanceled == TRUE)
{
m_AsyncCanceled = FALSE;
setDiagRec(DRIVER_ERROR, IDS_S1_008);
}
m_StmtState = STMT_ALLOCATED;
setRowCount(-1);
break;
case SQL_NEED_DATA:
case SQL_NO_DATA:
case SQL_INVALID_HANDLE:
default:
break;
}
return rc;
}
SQLRETURN CStmt::GetCursorName(SQLWCHAR *CursorNameW,
SQLSMALLINT BufferLength,
SQLSMALLINT *NameLengthPtr)
{
SQLRETURN rc = SQL_SUCCESS;
short strLen = 0;
int translen = 0;
char transError[MAX_TRANSLATE_ERROR_MSG_LEN];
unsigned long retCode;
clearError();
m_CurrentOdbcAPI = SQL_API_SQLGETCURSORNAME;
if(m_CursorName[0] != '\0')
strLen = strlen((const char *)m_CursorName);
else
strLen = strlen((const char *)m_StmtLabel);
if (CursorNameW != NULL)
{
if(m_CursorName[0] != '\0')
{
// translate from UTF8 to WCHAR
rc = UTF8ToWChar((char*)m_CursorName, strLen, (wchar_t *)CursorNameW, BufferLength, &translen, transError);
}
else
{
// translate from UTF8 to WCHAR
rc = UTF8ToWChar((char*)m_StmtLabel, strLen, (wchar_t *)CursorNameW, BufferLength, &translen, transError);
}
if (rc == SQL_SUCCESS)
strLen = translen;
else if (rc == SQL_SUCCESS_WITH_INFO)
setDiagRec(DRIVER_ERROR, IDS_01_004);
}
if (NameLengthPtr != NULL)
*NameLengthPtr = strLen*2;
return rc ;
}
SQLRETURN CStmt::SetCursorName(SQLWCHAR *CursorNameW,
SQLSMALLINT NameLength)
{
SQLRETURN rc = SQL_SUCCESS;
int translen = 0;
char transError[MAX_TRANSLATE_ERROR_MSG_LEN];
CHANDLECOLLECT::iterator i;
clearError();
m_CurrentOdbcAPI = SQL_API_SQLSETCURSORNAME;
if(NameLength == SQL_NTS)
NameLength = wcslen(CursorNameW);
NameLength = min(NameLength, 128); // max cursorname length is 128
// translate from WCHAR to UTF8
rc = WCharToUTF8((wchar_t*)CursorNameW, NameLength, (char*)m_CursorName, sizeof(m_CursorName), &translen, transError);
if (rc == SQL_SUCCESS_WITH_INFO)
setDiagRec(DRIVER_ERROR, IDS_01_004);
if ((strncmp(m_CursorName, "SQLCUR", 6) == 0) || (strncmp(m_CursorName, "SQL_CUR", 7) == 0))
{
setDiagRec(DRIVER_ERROR, IDS_34_000);
return SQL_ERROR;
}
for (i = m_ConnectHandle->m_StmtCollect.begin() ; i != m_ConnectHandle->m_StmtCollect.end() ; ++i)
{
CStmt* pStmt = ((CStmt *)(*i));
if ((strncmp(pStmt->m_CursorName, m_CursorName, strlen(m_CursorName)) == 0) && (pStmt != this))
{
setDiagRec(DRIVER_ERROR, IDS_3C_000);
return SQL_ERROR;
}
}
return rc;
}
SQLRETURN CStmt::Cancel()
{
SQLRETURN rc = SQL_SUCCESS;
// Check if we are cancelling SQLParamData or SQLPutData API
m_CurrentOdbcAPI = SQL_API_SQLCANCEL;
switch (m_StmtState)
{
case STMT_PARAM_DATA_NOT_CALLED:
case STMT_PUT_DATA_NOT_CALLED:
case STMT_PUT_DATA_CALLED:
revertStmtState();
break;
default:
break;
}
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE )
{
if(m_ConnectHandle->m_IgnoreCancel == false)
{
m_AsyncCanceled = TRUE;
sendStopServer();
rc = SQL_SUCCESS;
}
else
{
m_CancelCalled = true;
setDiagRec(DRIVER_ERROR, IDS_HY_018);
rc = SQL_ERROR;
}
}
else if (getODBCAppVersion()== SQL_OV_ODBC2)
{
m_AsyncEnable = SQL_ASYNC_ENABLE_OFF;
rc = Close(SQL_CLOSE);
m_AsyncEnable = SQL_ASYNC_ENABLE_ON;
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "Cancel - GetExitCodeThread()");
return SQL_ERROR;
}
}
}
else if (m_SyncThread != NULL)
{
if (GetExitCodeThread(m_SyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
{
if(m_ConnectHandle->m_IgnoreCancel == false)
{
m_AsyncCanceled = TRUE;
sendStopServer();
rc = SQL_SUCCESS;
}
else
{
setDiagRec(DRIVER_ERROR, IDS_HY_018);
rc = SQL_ERROR;
}
}
else if (getODBCAppVersion()== SQL_OV_ODBC2)
rc = Close(SQL_CLOSE);
}
else
{
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "Cancel - GetExitCodeThread()");
return SQL_ERROR;
}
}
return rc;
}
SQLRETURN CStmt::ColAttribute(SQLUSMALLINT ColumnNumber,
SQLUSMALLINT FieldIdentifier,
SQLPOINTER CharacterAttributePtr,
SQLSMALLINT BufferLength,
SQLSMALLINT *StringLengthPtr,
SQLPOINTER NumericAttributePtr)
{
CDesc *pDesc;
SQLRETURN rc = SQL_SUCCESS;
SQLPOINTER ValuePtr;
SQLINTEGER lStringLength;
SQLSMALLINT sTmp;
SQLINTEGER DataType;
clearError();
DataType = DRVR_PENDING;
m_CurrentOdbcAPI = SQL_API_SQLCOLATTRIBUTE;
if ((m_StmtState == STMT_EXECUTED_NO_RESULT) &&
(m_StmtQueryType != SQL_SELECT_UNIQUE))
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
if (m_StmtState == STMT_PREPARED_NO_RESULT && FieldIdentifier != SQL_DESC_COUNT)
{
setDiagRec(DRIVER_ERROR, IDS_07_005);
return SQL_ERROR;
}
if (ColumnNumber == 0)
{
setDiagRec(DRIVER_ERROR, IDS_07_009);
return SQL_ERROR;
}
pDesc = m_ImpRowDesc;
switch (FieldIdentifier)
{
case SQL_DESC_AUTO_UNIQUE_VALUE:
case SQL_DESC_CASE_SENSITIVE:
case SQL_DESC_DISPLAY_SIZE:
case SQL_DESC_NUM_PREC_RADIX:
case SQL_DESC_OCTET_LENGTH:
DataType = SQL_IS_INTEGER;
ValuePtr = NumericAttributePtr;
break;
case SQL_DESC_LENGTH:
case SQL_COLUMN_LENGTH:
case SQL_COLUMN_PRECISION:
DataType = SQL_IS_UINTEGER;
ValuePtr = NumericAttributePtr;
break;
case SQL_DESC_CONCISE_TYPE:
case SQL_DESC_COUNT:
case SQL_DESC_FIXED_PREC_SCALE:
case SQL_DESC_PRECISION:
case SQL_DESC_SCALE:
case SQL_DESC_NULLABLE:
case SQL_DESC_SEARCHABLE:
case SQL_DESC_TYPE:
case SQL_DESC_UNNAMED:
case SQL_DESC_UNSIGNED:
case SQL_DESC_UPDATABLE:
case SQL_COLUMN_SCALE:
DataType = SQL_IS_SMALLINT;
ValuePtr = &sTmp;
break;
case SQL_DESC_BASE_COLUMN_NAME:
case SQL_DESC_BASE_TABLE_NAME:
case SQL_DESC_CATALOG_NAME:
case SQL_DESC_LABEL:
case SQL_DESC_LITERAL_PREFIX:
case SQL_DESC_LITERAL_SUFFIX:
case SQL_DESC_LOCAL_TYPE_NAME:
case SQL_DESC_NAME:
case SQL_DESC_SCHEMA_NAME:
case SQL_DESC_TYPE_NAME:
case SQL_DESC_TABLE_NAME:
ValuePtr = CharacterAttributePtr;
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_091);
return SQL_ERROR;
}
rc = pDesc->GetDescField(ColumnNumber, FieldIdentifier, ValuePtr, BufferLength, &lStringLength);
if (DataType == SQL_IS_SMALLINT)
{
if (NumericAttributePtr != NULL)
*(SQLSMALLINT *)NumericAttributePtr = (SQLSMALLINT)sTmp;
}
if (DataType == DRVR_PENDING)
if (StringLengthPtr != NULL)
*StringLengthPtr = lStringLength;
return rc;
}
SQLRETURN CStmt::SendExecute(BOOL SkipProcess)
{
SQLRETURN rc;
SQLRETURN rctrack = 0; // To keep track of SUCCESS_WITH_INFO in case of data truncation.
SQLSMALLINT AppParamCount;
SQLSMALLINT ParamNumber;
SQLULEN RowNumber;
SQLINTEGER ODBCAppVersion;
if (m_ConnectHandle->getConnectionStatus() == SQL_CD_TRUE)
{
clearError();
setDiagRec(DRIVER_ERROR, IDS_08_S01, -20005);
return SQL_ERROR;
}
if (! SkipProcess)
{
clearError();
setDiagRowCount(-1, -1);
if (m_StmtState == STMT_FETCHED)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
m_AppParamDesc->GetDescField(0, SQL_DESC_COUNT, &AppParamCount, SQL_IS_SMALLINT, NULL);
if (AppParamCount < m_NumParams)
{
setDiagRec(DRIVER_ERROR, IDS_07_002);
return SQL_ERROR;
}
InitInputValueList();
ParamNumber = 0;
RowNumber = 1;
ODBCAppVersion = getODBCAppVersion();
if (m_NumParams > 0)
{
rc = m_AppParamDesc->BuildValueList(this, m_NumParams, m_ImpParamDesc,
ODBCAppVersion, ParamNumber, RowNumber, &m_InputValueList, m_ParamBuffer);
switch (rc)
{
case SQL_SUCCESS:
break;
case SQL_SUCCESS_WITH_INFO:
rctrack = SQL_SUCCESS_WITH_INFO;
break;
case SQL_NEED_DATA:
m_CurrentParam = ParamNumber;
m_CurrentRow = RowNumber;
m_CurrentParamStatus = SQL_DATA_AT_EXEC;
return SQL_NEED_DATA;
default:
return SQL_ERROR;
}
}
m_ImpParamDesc->setRowsProcessed(RowNumber);
if (m_StmtQueryType == SQL_SELECT_UNIQUE)
{
// Reset the Fetch related member elements
m_RowsFetched = -1;
m_ImpRowDesc->setRowsProcessed(0);
m_ImpRowDesc->setDescArrayStatus(1);
}
if(m_NumParams > 0)
{
if(m_RowIdMap.size()==0)//all rows contained ERRORS
{
RowNumber = 0;
}
else if(RowNumber == m_RowIdMap.size())
m_RowIdMap.clear();//don't need the row id map since each client side row id mathces the server side row id
else //there are both, successful and failed rows
RowNumber = m_RowIdMap.size();
}
if(RowNumber>0)
{
m_SrvrCallContext.odbcAPI = SQL_API_SQLEXECUTE;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.connectionTimeout = m_ConnectHandle->getConnectionTimeout();
m_SrvrCallContext.u.executeParams.queryTimeout = m_QueryTimeout;
m_SrvrCallContext.u.executeParams.stmtLabel = m_StmtLabel;
m_SrvrCallContext.u.executeParams.cursorName = m_CursorName;
m_SrvrCallContext.u.executeParams.sqlStmtType = m_StmtType;
m_SrvrCallContext.u.executeParams.rowCount = RowNumber;
m_SrvrCallContext.u.executeParams.inputValueList = &m_InputValueList;
m_SrvrCallContext.u.executeParams.asyncEnable = m_AsyncEnable;
m_SrvrCallContext.u.executeParams.holdableCursor = m_CursorHoldable;
}
else
{
setDiagRowCount(0, -1);
setRowCount(0);
return rc;
}
}
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if ((m_AsyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendExecute - _beginthreadex()");
rc = SQL_ERROR;
}
ResumeThread(m_AsyncThread);
rc = SQL_STILL_EXECUTING;
Sleep(0);
}
else
{
if ((m_SyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendPrepare - _beginthreadex()");
rc = SQL_ERROR;
}
else
{
ResumeThread(m_SyncThread);
WaitForSingleObject(m_SyncThread,INFINITE);
GetExitCodeThread(m_SyncThread, &m_ThreadStatus);
rc = m_ThreadStatus;
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
}
// rc = ThreadControlProc(&m_SrvrCallContext);
}
if(m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if(rctrack == SQL_SUCCESS_WITH_INFO)
m_WarningSetBeforeAsync = true;
else
m_WarningSetBeforeAsync = false;
}
else if (rctrack == SQL_SUCCESS_WITH_INFO && rc != SQL_ERROR)
rc = rctrack;
return rc;
}
SQLRETURN CStmt::Execute()
{
SQLRETURN rc;
BOOL SkipProcess = FALSE;
m_CurrentOdbcAPI = SQL_API_SQLEXECUTE;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
{
rc = m_ThreadStatus;
if(rc == SQL_SUCCESS && m_WarningSetBeforeAsync)
rc = SQL_SUCCESS_WITH_INFO;
}
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "Execute - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
SkipProcess = TRUE;
rc = SendExecute(SkipProcess);
}
}
else
rc = SendExecute(SkipProcess);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
if (m_StmtType == TYPE_SELECT || m_StmtType == TYPE_CALL)
m_StmtState = STMT_EXECUTED;
else
m_StmtState = STMT_EXECUTED_NO_RESULT;
m_isClosed = false;
if (m_StmtQueryType == SQL_SELECT_UNIQUE && m_RowCount == 0)
m_StmtState = STMT_EXECUTED_NO_RESULT;
break;
case SQL_STILL_EXECUTING:
m_StmtState = STMT_STILL_EXECUTING;
break;
case SQL_NEED_DATA:
m_StmtState = STMT_PARAM_DATA_NOT_CALLED;
break;
case SQL_ERROR:
if (m_AsyncCanceled == TRUE)
{
m_AsyncCanceled = FALSE;
setDiagRec(DRIVER_ERROR, IDS_S1_008);
}
if (m_StmtType == TYPE_SELECT)
m_StmtState = STMT_PREPARED;
else
m_StmtState = STMT_PREPARED_NO_RESULT;
setRowCount(-1);
break;
case SQL_NO_DATA:
if (m_StmtQueryType == SQL_SELECT_UNIQUE)
{
m_StmtState = STMT_EXECUTED_NO_RESULT;
rc = SQL_SUCCESS;
}
break;
case SQL_INVALID_HANDLE:
default:
break;
}
return rc;
}
SQLRETURN CStmt::SendParamData(BOOL SkipProcess, SQLPOINTER *ValuePtrPtr)
{
SQLRETURN rc = SQL_SUCCESS;
SQLSMALLINT ParamNumber;
SQLULEN RowNumber;
SQLULEN AppArrayStatusSize;
SQLINTEGER ODBCAppVersion;
unsigned long retCode;
UCHAR errorMsg[MAX_TRANSLATE_ERROR_MSG_LEN];
if (m_ConnectHandle->getConnectionStatus() == SQL_CD_TRUE)
{
clearError();
setDiagRec(DRIVER_ERROR, IDS_08_S01, -20005);
return SQL_ERROR;
}
if (! SkipProcess)
{
clearError();
if (m_CurrentParam != -1)
{
switch (m_CurrentParamStatus)
{
case SQL_DATA_AT_EXEC:
retCode = m_AppParamDesc->ParamData(m_CurrentRow, m_CurrentParam, ValuePtrPtr);
if (retCode != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
rc = SQL_ERROR;
}
else
{
m_CurrentParamStatus = SQL_WAITING_FOR_DATA;
rc = SQL_NEED_DATA;
}
return rc;
case SQL_WAITING_FOR_DATA:
// SQLParamData is called without calling SQLPutData
setDiagRec(DRIVER_ERROR, IDS_HY_010);
return SQL_ERROR;
case SQL_RECEIVING_DATA:
ODBCAppVersion = getODBCAppVersion();
ParamNumber = m_CurrentParam;
RowNumber = m_CurrentRow;
// Update the current DataAtExecData Parameter value in m_InputValueList
// and then proceed to Build the inputList
retCode = m_ImpParamDesc->AssignDataAtExecValue(&m_DataAtExecData, m_AppParamDesc,
ODBCAppVersion, ParamNumber, RowNumber, &m_InputValueList,
errorMsg,
sizeof(errorMsg));
if (retCode != SQL_SUCCESS)
{
if (errorMsg[0] != '\0')
setDiagRec(DRIVER_ERROR, retCode, 0, (char *)errorMsg, NULL, RowNumber, ParamNumber);
else
setDiagRec(DRIVER_ERROR, retCode, 0, NULL, NULL, RowNumber, ParamNumber);
switch (retCode)
{
case IDS_01_004:
case IDS_01_S07:
case IDS_188_DRVTODS_TRUNC:
rc = SQL_SUCCESS_WITH_INFO;
break;
case IDS_22_001:
default:
rc = SQL_ERROR;
break;
}
}
else
rc = SQL_SUCCESS;
if (rc == SQL_ERROR)
return rc;
rc = m_AppParamDesc->BuildValueList(this, m_NumParams, m_ImpParamDesc, ODBCAppVersion, ParamNumber, RowNumber,
&m_InputValueList, m_ParamBuffer);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
break;
case SQL_NEED_DATA:
m_CurrentParam = ParamNumber;
m_CurrentRow = RowNumber;
retCode = m_AppParamDesc->ParamData(m_CurrentRow, m_CurrentParam, ValuePtrPtr);
if (retCode != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
rc = SQL_ERROR;
}
else
{
m_CurrentParamStatus = SQL_WAITING_FOR_DATA;
rc = SQL_NEED_DATA;
}
return rc;
default:
setDiagRec(DRIVER_ERROR, rc);
return rc;
}
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_000);
return SQL_ERROR;
}
}
else
{
setDiagRec(DRIVER_ERROR, IDS_HY_010);
return SQL_ERROR;
}
m_SrvrCallContext.odbcAPI = SQL_API_SQLPARAMDATA;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.connectionTimeout = m_ConnectHandle->getConnectionTimeout();
m_SrvrCallContext.u.executeParams.queryTimeout = m_QueryTimeout;
m_SrvrCallContext.u.executeParams.stmtLabel = m_StmtLabel;
m_SrvrCallContext.u.executeParams.cursorName = m_CursorName;
m_SrvrCallContext.u.executeParams.sqlStmtType = m_StmtType;
m_SrvrCallContext.u.executeParams.rowCount = RowNumber;
m_SrvrCallContext.u.executeParams.inputValueList = &m_InputValueList;
m_SrvrCallContext.u.executeParams.asyncEnable = m_AsyncEnable;
m_ImpParamDesc->setRowsProcessed(RowNumber);
}
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if ((m_AsyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendParamData - _beginthreadex()");
rc = SQL_ERROR;
}
ResumeThread(m_AsyncThread);
rc = SQL_STILL_EXECUTING;
Sleep(0);
}
else
{
if ((m_SyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendPrepare - _beginthreadex()");
rc = SQL_ERROR;
}
else
{
ResumeThread(m_SyncThread);
WaitForSingleObject(m_SyncThread,INFINITE);
GetExitCodeThread(m_SyncThread, &m_ThreadStatus);
rc = m_ThreadStatus;
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
}
// rc = ThreadControlProc(&m_SrvrCallContext);
}
if (rc == SQL_ERROR)
{
#ifdef _WIN64
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &AppArrayStatusSize, SQL_C_UBIGINT, NULL);
#else
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &AppArrayStatusSize, SQL_IS_UINTEGER, NULL);
#endif
m_ImpParamDesc->setDescArrayStatus(AppArrayStatusSize,SQL_PARAM_ERROR);
}
return rc;
}
SQLRETURN CStmt::ParamData(SQLPOINTER *ValuePtrPtr)
{
BOOL SkipProcess = FALSE;
SQLRETURN rc;
//insert >16m lob
if (m_CurrentOdbcAPI == SRVR_API_UPDATELOB)
{
if (m_ConnectHandle->lobHandleLenSave == 0)
return SQL_ERROR;
if (m_StmtState == STMT_PARAM_DATA_NOT_CALLED)
{
m_CurrentParamStatus = SQL_WAITING_FOR_DATA;
return SQL_NEED_DATA;
}
else
{
rc = UpdateLob(0, m_ConnectHandle->lobHandleSave, m_ConnectHandle->lobHandleLenSave, 0, 0, 0, m_DataAtExecData.dataValue._length, (BYTE *)m_DataAtExecData.dataValue._buffer);
m_ConnectHandle->lobHandleLenSave == 0;
free(m_ConnectHandle->lobHandleSave);
m_ConnectHandle->lobHandleSave = NULL;
return rc;
}
}
m_CurrentOdbcAPI = SQL_API_SQLPARAMDATA;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
rc = m_ThreadStatus;
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "Execute - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
SkipProcess = TRUE;
rc = SendParamData(SkipProcess, ValuePtrPtr);
}
}
else
rc = SendParamData(SkipProcess, ValuePtrPtr);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
if (m_StmtType == TYPE_SELECT)
m_StmtState = STMT_EXECUTED;
else
m_StmtState = STMT_EXECUTED_NO_RESULT;
break;
case SQL_STILL_EXECUTING:
m_StmtState = STMT_STILL_EXECUTING;
break;
case SQL_NEED_DATA:
m_StmtState = STMT_PUT_DATA_NOT_CALLED;
break;
case SQL_ERROR:
if (m_AsyncCanceled == TRUE)
{
m_AsyncCanceled = FALSE;
setDiagRec(DRIVER_ERROR, IDS_S1_008);
}
revertStmtState();
break;
case SQL_NO_DATA:
if (m_StmtQueryType == SQL_SELECT_UNIQUE)
m_StmtState = STMT_EXECUTED_NO_RESULT;
break;
case SQL_INVALID_HANDLE:
default:
break;
}
return rc;
}
SQLRETURN CStmt::PutData(SQLPOINTER DataPtr,
SQLLEN StrLen_or_Ind)
{
SQLRETURN rc = SQL_SUCCESS;
SQLSMALLINT DataType;
SQLSMALLINT ODBCDataType;
SQLINTEGER OctetLength;
SQLPOINTER AllocDataPtr;
unsigned long retCode;
SQLLEN *StrLenPtr;
SQLINTEGER StrLen;
SQLSMALLINT ParameterType;
if (m_CurrentOdbcAPI == SRVR_API_UPDATELOB)
{
if (m_CurrentParamStatus == SQL_WAITING_FOR_DATA)
{
if (m_DataAtExecData.dataValue._buffer != NULL)
{
delete m_DataAtExecData.dataValue._buffer;
m_DataAtExecData.dataValue._buffer = NULL;
m_DataAtExecData.dataValue._length = 0;
}
m_CurrentParamStatus = SQL_RECEIVING_DATA;
}
else
{
OctetLength = m_DataAtExecData.dataValue._length;
}
if (StrLen_or_Ind == SQL_NTS)
StrLen = strlen((const char *)DataPtr);
else
StrLen = StrLen_or_Ind;
OctetLength += StrLen;
AllocDataPtr = new BYTE[OctetLength];
if (m_DataAtExecData.dataValue._buffer != NULL)
{
memcpy((unsigned char *)AllocDataPtr, (unsigned char*)m_DataAtExecData.dataValue._buffer, m_DataAtExecData.dataValue._length);
delete m_DataAtExecData.dataValue._buffer;
m_DataAtExecData.dataValue._buffer = NULL;
}
m_DataAtExecData.dataValue._buffer = (unsigned char *)AllocDataPtr;
memcpy(m_DataAtExecData.dataValue._buffer + m_DataAtExecData.dataValue._length, DataPtr, StrLen);
m_DataAtExecData.dataValue._length = OctetLength;
m_StmtState = STMT_PUT_DATA_CALLED;
return rc;
}
m_CurrentOdbcAPI = SQL_API_SQLPUTDATA;
clearError();
if (m_CurrentParam == -1)
{
setDiagRec(DRIVER_ERROR, IDS_HY_010);
rc = SQL_ERROR;
goto updateStmtState;
}
switch (m_CurrentParamStatus)
{
case SQL_WAITING_FOR_DATA: // First time SQLPutData is called for this parameter
if ((retCode = m_AppParamDesc->GetParamType(m_CurrentRow, m_CurrentParam, DataType,
StrLenPtr)) != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
rc = SQL_ERROR;
goto updateStmtState;
}
if (StrLenPtr == NULL)
{
setDiagRec(DRIVER_ERROR, IDS_HY_000);
rc = SQL_ERROR;
goto updateStmtState;
}
if ((retCode = m_ImpParamDesc->GetParamSQLInfo(m_CurrentRow, m_CurrentParam, ParameterType,
ODBCDataType)) != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
rc = SQL_ERROR;
goto updateStmtState;
}
if (DataType == SQL_C_DEFAULT)
{
if ((retCode = getCDefault(ParameterType, getODBCAppVersion(), DataType)) != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
rc = SQL_ERROR;
goto updateStmtState;
}
}
m_DataAtExecData.dataType = DataType;
m_DataAtExecData.dataCharset = 0;
StrLen = StrLen_or_Ind;
switch (StrLen_or_Ind)
{
case SQL_DEFAULT_PARAM:
setDiagRec(DRIVER_ERROR, IDS_07_S01);
rc = SQL_ERROR;
goto updateStmtState;
break;
case SQL_NULL_DATA:
m_DataAtExecData.dataInd = -1;
if (m_DataAtExecData.dataValue._buffer != NULL)
delete m_DataAtExecData.dataValue._buffer;
m_DataAtExecData.dataValue._buffer = NULL;
m_DataAtExecData.dataValue._length = 0;
m_DataAtExecDataBufferSize = 0;
break;
case SQL_NTS:
if (DataType == SQL_C_WCHAR)
{
StrLen = wcslen((const wchar_t *)DataPtr);
StrLen = StrLen * 2;
}
else
StrLen = strlen((const char *)DataPtr); // Note No Break
default:
if (StrLen < 0)
{
setDiagRec(DRIVER_ERROR, IDS_HY_090);
rc = SQL_ERROR;
goto updateStmtState;
}
switch (DataType)
{
case SQL_C_CHAR:
case SQL_C_BINARY:
case SQL_C_WCHAR:
// Get the Length Specified at exec Time
if (*StrLenPtr == SQL_DATA_AT_EXEC)
OctetLength = 4096+2;
else
OctetLength = (*StrLenPtr * -1) + SQL_LEN_DATA_AT_EXEC_OFFSET+2;
if (StrLen > OctetLength)
{
setDiagRec(DRIVER_ERROR, IDS_22_001);
rc = SQL_ERROR;
goto updateStmtState;
}
break;
default:
if (retCode = getOctetLength(ODBCDataType,
getODBCAppVersion(),
DataPtr,
StrLen_or_Ind,
DataType,
OctetLength) != SQL_SUCCESS)
{
setDiagRec(DRIVER_ERROR, retCode);
rc = SQL_ERROR;
goto updateStmtState;
}
StrLen = OctetLength;
break;
}
AllocDataPtr = new BYTE[OctetLength];
if (AllocDataPtr == NULL)
{
setDiagRec(DRIVER_ERROR, IDS_HY_001);
rc = SQL_ERROR;
goto updateStmtState;
}
m_DataAtExecDataBufferSize = OctetLength;
m_DataAtExecData.dataInd = 0;
if (m_DataAtExecData.dataValue._buffer != NULL)
delete m_DataAtExecData.dataValue._buffer;
m_DataAtExecData.dataValue._buffer = (unsigned char *)AllocDataPtr;
memcpy(AllocDataPtr, DataPtr, StrLen);
m_DataAtExecData.dataValue._length = StrLen;
break;
}
m_CurrentParamStatus = SQL_RECEIVING_DATA;
break;
case SQL_RECEIVING_DATA:
switch (m_DataAtExecData.dataType)
{
case SQL_C_CHAR:
case SQL_C_BINARY:
case SQL_C_WCHAR:
StrLen = StrLen_or_Ind;
switch (StrLen_or_Ind)
{
case SQL_NULL_DATA: // Null Data being concatenated,
case SQL_DEFAULT_PARAM:
setDiagRec(DRIVER_ERROR, IDS_HY_020);
rc = SQL_ERROR;
goto updateStmtState;
case SQL_NTS:
if(m_DataAtExecData.dataType == SQL_C_WCHAR)
{
StrLen = wcslen((const wchar_t *)DataPtr);
StrLen = StrLen * 2;
}
else
StrLen = strlen((const char *)DataPtr);
default:
if (StrLen < 0)
{
setDiagRec(DRIVER_ERROR, IDS_HY_090);
rc = SQL_ERROR;
goto updateStmtState;
}
if(m_DataAtExecData.dataType == SQL_C_WCHAR)
{
if (m_DataAtExecData.dataValue._length + StrLen > m_DataAtExecDataBufferSize)
{
setDiagRec(DRIVER_ERROR, IDS_22_001);
rc = SQL_ERROR;
goto updateStmtState;
}
}
else
{
if (m_DataAtExecData.dataValue._length + StrLen > m_DataAtExecDataBufferSize)
{
setDiagRec(DRIVER_ERROR, IDS_22_001);
rc = SQL_ERROR;
goto updateStmtState;
}
}
memcpy(m_DataAtExecData.dataValue._buffer + m_DataAtExecData.dataValue._length, DataPtr, StrLen);
m_DataAtExecData.dataValue._length += StrLen;
break;
}
break;
default: // Non-character or non-Binary data being sent in pieces
setDiagRec(DRIVER_ERROR, IDS_HY_019);
rc = SQL_ERROR;
break;
}
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_010);
rc = SQL_ERROR;
}
updateStmtState:
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
m_StmtState = STMT_PUT_DATA_CALLED;
break;
case SQL_ERROR:
revertStmtState();
break;
case SQL_STILL_EXECUTING:
case SQL_NEED_DATA:
case SQL_NO_DATA:
case SQL_INVALID_HANDLE:
default:
break;
}
return rc;
}
BOOL CStmt::setFetchOutputPerf(long rowsFetched, SQL_DataValue_def*& outputDataValue)
{
long totalLength;
m_RowsFetched = rowsFetched;
m_ResultsetRowsFetched += rowsFetched;
m_CurrentRowFetched = 0;
m_CurrentRowInRowset = 0;
m_RowsetSize = 0;
m_ImpRowDesc->setRowsProcessed(rowsFetched);
if (m_FetchDataValue.rowAddress != NULL )
{
delete[] m_FetchDataValue.rowAddress;
m_FetchDataValue.rowAddress = NULL;
}
if (m_outputDataValue._length != 0 &&
m_outputDataValue._buffer != NULL)
{
delete m_outputDataValue._buffer;
m_outputDataValue._buffer = NULL;
m_outputDataValue._length = 0;
}
totalLength = outputDataValue->_length;
if(totalLength > 0)
{
m_outputDataValue._buffer = (unsigned char*)new char[totalLength+1];
if (m_outputDataValue._buffer == NULL)
return FALSE;
memset(m_outputDataValue._buffer, 0, totalLength+1);
}
m_outputDataValue._length = outputDataValue->_length;
if(outputDataValue->_length > 0)
{
memcpy(m_outputDataValue._buffer,outputDataValue->_buffer,outputDataValue->_length);
m_outputDataValue._buffer[totalLength] = '\0';
}
if (m_StmtQueryType == SQL_SELECT_UNIQUE)
{
if (outputDataValue->_buffer != NULL)
{
delete outputDataValue->_buffer;
outputDataValue->_length = 0;
outputDataValue->_buffer = NULL;
}
}
outputDataValue = &m_outputDataValue;
m_FetchDataValue.numberOfElements = m_outputDataValue._length;
m_FetchDataValue.numberOfRows = rowsFetched;
if(rowsFetched > 0)
{
m_FetchDataValue.rowAddress = new LONG_PTR[rowsFetched];
if (m_FetchDataValue.rowAddress != NULL)
return TRUE;
else
{
delete m_outputDataValue._buffer;
m_outputDataValue._buffer =NULL;
m_outputDataValue._length = 0;
return FALSE;
}
}
return TRUE;
}
// This function has been overloaded to use in RWRS binding scenario
BOOL CStmt::setFetchOutputPerf(SQL_DataValue_def*& outputDataValue, long rowsFetched)
{
IDL_long memOffSet = 0;
IDL_long VarOffSet = 0;
IDL_long IndOffSet = 0;
BYTE *memPtr = NULL;
BYTE *IndicatorPtr = NULL;
IDL_long count = 0;
int ColumnCount = 0;
int index=0;
SQLINTEGER SQLCharset=0;
SQLSMALLINT SQLDataType=0;
SQLSMALLINT SQLDatetimeCode=0;
SQLINTEGER SQLMaxLength=0;
SQLINTEGER SQLOctetLength=0;
SQLSMALLINT SQLPrecision=0;
SQLSMALLINT SQLUnsigned=0;
SQLSMALLINT SQLNullable=0;
m_RowsFetched = rowsFetched;
m_ResultsetRowsFetched += rowsFetched;
m_CurrentRowFetched = 0;
m_CurrentRowInRowset = 0;
m_RowsetSize = 0;
m_ImpRowDesc->setRowsProcessed(rowsFetched);
if (m_FetchDataValue.rowAddress != NULL )
{
delete[] m_FetchDataValue.rowAddress;
m_FetchDataValue.rowAddress = NULL;
}
if (m_outputDataValue._length != 0 &&
m_outputDataValue._buffer != NULL)
{
delete m_outputDataValue._buffer;
m_outputDataValue._buffer = NULL;
m_outputDataValue._length = 0;
}
count = getImpDescCount();
if (m_ColumnIndexes != NULL)
{
delete[] m_ColumnIndexes;
m_ColumnIndexes=NULL;
}
if (m_SwapInfo != NULL)
{
for (int r = 0; r < m_SwapInfo_NumRows; r++)
{
if (m_SwapInfo[r] != NULL)
delete[] (m_SwapInfo[r]);
}
delete[] m_SwapInfo;
m_SwapInfo = NULL;
m_SwapInfo_NumRows = 0;
}
m_ColumnIndexes = new long[count*2]; // Two indexes for each column
memset((void *)m_ColumnIndexes, 0, sizeof(long)*count*2);
memPtr = outputDataValue->_buffer;
for (ColumnCount = 0; ColumnCount < count ; ColumnCount++)
{
getImpRowData(ColumnCount+1, SQLDataType, SQLMaxLength, SQLNullable);
index = 2*ColumnCount;
if (SQLNullable)
{
memOffSet = ((memOffSet + 2 - 1) >> 1) << 1;
IndOffSet = memOffSet;
IndicatorPtr = memPtr + IndOffSet;
memOffSet += 2 ;
m_ColumnIndexes[index] = IndOffSet;
}
else
m_ColumnIndexes[index] = -1;
switch (SQLDataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_VARCHAR:
VarOffSet = memOffSet;
memOffSet += SQLMaxLength;
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
if(SQLMaxLength>SHRT_MAX)
{
memOffSet = ((memOffSet + 4 - 1) >> 2) << 2;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength + 4;
}
else
{
memOffSet = ((memOffSet + 2 - 1) >> 1) << 1;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength + 2;
}
break;
case SQLTYPECODE_BLOB:
case SQLTYPECODE_CLOB:
memOffSet = ((memOffSet + 2 - 1) >> 1) << 1;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength + 2;
break;
case SQLTYPECODE_INTERVAL:
VarOffSet = memOffSet;
memOffSet += SQLMaxLength;
break;
case SQLTYPECODE_VARCHAR_LONG:
memOffSet = ((memOffSet + 2 - 1) >> 1) << 1;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength + 2;
break;
case SQLTYPECODE_SMALLINT:
memOffSet = ((memOffSet + 2 - 1) >> 1) << 1;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength;
break;
case SQLTYPECODE_SMALLINT_UNSIGNED:
memOffSet = ((memOffSet + 2 - 1) >> 1) << 1;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
case SQLTYPECODE_INTEGER:
memOffSet = ((memOffSet + 4 - 1) >> 2) << 2;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
case SQLTYPECODE_INTEGER_UNSIGNED:
memOffSet = ((memOffSet + 4 - 1) >> 2) << 2;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
case SQLTYPECODE_LARGEINT:
case SQLTYPECODE_LARGEINT_UNSIGNED:
memOffSet = ((memOffSet + 8 - 1) >> 3) << 3;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
case SQLTYPECODE_IEEE_REAL:
//memOffSet = ((memOffSet + 4 - 1) >> 2) << 2;
memOffSet = ((memOffSet + 8 - 1) >> 3) << 3;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
case SQLTYPECODE_IEEE_FLOAT:
case SQLTYPECODE_IEEE_DOUBLE:
memOffSet = ((memOffSet + 8 - 1) >> 3) << 3;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
case SQLTYPECODE_DATETIME:
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
case SQLTYPECODE_DECIMAL_UNSIGNED:
VarOffSet = memOffSet;
memOffSet += SQLMaxLength;
break;
case SQLTYPECODE_DECIMAL:
VarOffSet = memOffSet;
memOffSet += SQLMaxLength;
break;
case SQLTYPECODE_DECIMAL_LARGE_UNSIGNED:
VarOffSet = memOffSet;
memOffSet += SQLMaxLength;
break;
case SQLTYPECODE_DECIMAL_LARGE:
VarOffSet = memOffSet;
memOffSet += SQLMaxLength;
break;
case SQLTYPECODE_NUMERIC: //2
case SQLTYPECODE_NUMERIC_UNSIGNED: //-201
memOffSet = ((memOffSet + 8 - 1) >> 3) << 3;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
default:
//memOffSet = ((memOffSet + 8 - 1) >> 3) << 3;
VarOffSet = memOffSet;
memOffSet += SQLMaxLength ;
break;
}
m_ColumnIndexes[++index] = VarOffSet;
}
if ((rowsFetched > 0) && (memOffSet != outputDataValue->_length / rowsFetched))
{
setDiagRec(DRIVER_ERROR, IDS_21_002, 0, "Inconsistent memory offsets, data length, and rows fetched");
return FALSE;
}
if(outputDataValue->_length > 0)
{
m_outputDataValue._buffer = (unsigned char*)new char[outputDataValue->_length];
if (m_outputDataValue._buffer == NULL)
{
setDiagRec(DRIVER_ERROR, IDS_S1_001, 0, "Not enough memory to hold data");
return FALSE;
}
}
m_outputDataValue._length = outputDataValue->_length;
if(outputDataValue->_length > 0)
memcpy(m_outputDataValue._buffer,outputDataValue->_buffer,outputDataValue->_length);
outputDataValue = &m_outputDataValue;
m_FetchDataValue.numberOfElements = outputDataValue->_length;
m_FetchDataValue.numberOfRows = rowsFetched;
if (rowsFetched > 0)
{
m_FetchDataValue.rowAddress = new LONG_PTR[rowsFetched];
m_SwapInfo = new char*[rowsFetched];
m_SwapInfo_NumRows = rowsFetched;
for (int i = 0; i < rowsFetched; i++)
m_SwapInfo[i] = new char[count];
if (m_FetchDataValue.rowAddress == NULL || m_SwapInfo == NULL)
{
setDiagRec(DRIVER_ERROR, IDS_S1_001, 0, "Not enough memory");
delete m_outputDataValue._buffer;
m_outputDataValue._buffer =NULL;
m_outputDataValue._length = 0;
return FALSE;
}
//memset(m_SwapInfo,'N', rowsFetched * count);
for (int r = 0; r < rowsFetched; r++)
{
for (int c = 0; c < count; c++)
m_SwapInfo[r][c] = 'N';
}
}
return TRUE;
} // Rowwise rowset version of setFetchOutputPerf()
SQLRETURN CStmt::SendFetch(BOOL SkipProcess)
{
SQLRETURN rc = SQL_SUCCESS;
BOOL DispatchFetch = FALSE;
SQLULEN MaxRowCnt;
SQLINTEGER RecLength;
if (m_ConnectHandle->getConnectionStatus() == SQL_CD_TRUE)
{
clearError();
setDiagRec(DRIVER_ERROR, IDS_08_S01, -20005);
return SQL_ERROR;
}
if (m_StmtQueryType == SQL_SELECT_UNIQUE)
{
switch (m_StmtState)
{
case STMT_EXECUTED:
return SQL_SUCCESS;
case STMT_EXECUTED_NO_RESULT:
case STMT_FETCHED:
return SQL_NO_DATA;
default:
break;
}
}
if (! SkipProcess)
{
clearError();
if (m_StmtState == STMT_EXECUTED_NO_RESULT)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
if (m_MaxRows != 0)
{
if (m_RowNumber >= m_MaxRows)
return SQL_NO_DATA;
}
if (m_RowsFetched == -1 || m_RowsFetched == m_CurrentRowFetched)
{
// Calculate the Number of Rows to be fetched
#ifdef _WIN64
m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &MaxRowCnt, SQL_C_SBIGINT, NULL);
#else
m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &MaxRowCnt, SQL_IS_UINTEGER, NULL);
#endif
// Adjust MaxRowCnt to implement MaxRowValues
if (m_MaxRows != 0)
{
if (m_RowNumber + MaxRowCnt > m_MaxRows)
{
MaxRowCnt = m_MaxRows - m_RowNumber;
if (MaxRowCnt == 0)
return SQL_NO_DATA;
}
}
// If MaxRowCnt is more than 1, the application is using Block Cursor
// If MaxRowCnt is 1, the driver tries to do BulkFetch based on SQL_ATTR_CONCURRENCY
if (MaxRowCnt == 1)
{
if (m_Concurrency == SQL_CONCUR_READ_ONLY)
{
RecLength = m_ImpRowDesc->getRecLength();
if (RecLength > 0) // m_FetchBufferSize = 0 is equivalent to BulkFetch is disabled.
if (m_FetchBufferSize > RecLength)
MaxRowCnt = m_FetchBufferSize / RecLength;
if (m_MaxRows != 0)
{
if (m_RowNumber + MaxRowCnt > m_MaxRows)
{
MaxRowCnt = m_MaxRows - m_RowNumber;
if (MaxRowCnt == 0)
return SQL_NO_DATA;
}
}
}
}
// Added this code for future enabling. We can enable this for ABD, Do this does
// is if rows fetched by SQL is less the MAXROWCNT set then we can assume it as
// END OF DATA. Ando no need to send again FETCH call to Server. So that we can
// avoid one message transmission. On the Server side we internally call Fetch to
// make sure we reach END OF DATA.
// if (m_RowsFetched < MaxRowCnt)
// return SQL_NO_DATA;
m_SrvrCallContext.odbcAPI = SQL_API_SQLFETCH;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.connectionTimeout = m_ConnectHandle->getConnectionTimeout();
m_SrvrCallContext.u.fetchParams.queryTimeout = m_QueryTimeout;
if(m_spjNumResultSets > 0)
m_SrvrCallContext.u.fetchParams.stmtLabel = m_spjResultSets[m_spjCurrentResultSetIndex].spjStmtLabelName;
else
m_SrvrCallContext.u.fetchParams.stmtLabel = m_StmtLabel;
m_SrvrCallContext.u.fetchParams.maxRowCount = MaxRowCnt;
m_SrvrCallContext.u.fetchParams.maxRowLen = m_MaxLength;
m_SrvrCallContext.u.fetchParams.asyncEnable = m_AsyncEnable;
// Reset the Fetch related member elements
m_RowsFetched = -1;
DispatchFetch = TRUE;
m_ImpRowDesc->setRowsProcessed(0);
#ifdef _WIN64
m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &MaxRowCnt, SQL_C_UBIGINT, NULL);
#else
m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &MaxRowCnt, SQL_IS_UINTEGER, NULL);
#endif
m_ImpRowDesc->setDescArrayStatus(MaxRowCnt);
}
else
DispatchFetch = FALSE;
}
if (DispatchFetch)
{
this->m_preFetchThread.setSrvrCallContext(&m_SrvrCallContext);
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if ((m_AsyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendFetch - _beginthreadex()");
rc = SQL_ERROR;
}
ResumeThread(m_AsyncThread);
rc = SQL_STILL_EXECUTING;
Sleep(0);
}
else
{
if ((m_SyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendPrepare - _beginthreadex()");
rc = SQL_ERROR;
}
else
{
ResumeThread(m_SyncThread);
WaitForSingleObject(m_SyncThread,INFINITE);
GetExitCodeThread(m_SyncThread, &m_ThreadStatus);
rc = m_ThreadStatus;
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
}
//rc = ThreadControlProc(&m_SrvrCallContext);
}
}
return rc;
}
SQLRETURN CStmt::Fetch()
{
SQLRETURN rc, temprc;
SQLRETURN rcCopyData = SQL_SUCCESS;
BOOL SkipProcess = FALSE;
// Following variable and code is added because if application is 2.0 and is using
// SQL_ROWSET_SIZE option with SQLFetch instead of SQLExtendedFetch. So we are suppose to
// return one row at a time instead of 10 rows we fetch from server and move them
// into application buffer. Ex: Suppose we have 20 catalogs (like CAT1, CAT2.. Till
// CAT20) configured and application calls SQLTables for catalogs then we move
// 2 sets of 10 row chucks when application call SQLFetch we should return ONE ROW
// at a time NOT in set of 10 when SQLGetData or SQLBindCol is called. So set the
// m_DescArraySize variable to 1 and set it back to original before exiting the function.
SQLULEN tempMaxRowCnt;
SQLUINTEGER setMaxRowCntToOne = 1;
if (getODBCAppVersion() == SQL_OV_ODBC2)
{
#ifdef _WIN64
m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &tempMaxRowCnt, SQL_C_UBIGINT, NULL);
#else
m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &tempMaxRowCnt, SQL_IS_UINTEGER, NULL);
#endif
if (tempMaxRowCnt > 1)
{
temprc = m_AppRowDesc->SetDescField(0, SQL_DESC_ARRAY_SIZE, (SQLPOINTER)setMaxRowCntToOne, 0);
if (temprc == SQL_ERROR)
return temprc;
}
}
m_CurrentOdbcAPI = SQL_API_SQLFETCH;
m_CurrentFetchType = SQL_API_SQLFETCH;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
rc = m_ThreadStatus;
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "Fetch - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
SkipProcess = TRUE;
rc = SendFetch(SkipProcess);
}
}
else
rc = SendFetch(SkipProcess);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
rcCopyData = m_AppRowDesc->CopyData(this, m_NumResultCols, m_ImpRowDesc,
m_RowsFetched, m_CurrentRowFetched, m_RowNumber, m_RowsetSize);
m_ImpRowDesc->setRowsProcessed(m_RowsetSize);
m_StmtState = STMT_FETCHED;
m_CurrentRowInRowset = 1;
break;
case SQL_STILL_EXECUTING:
m_StmtState = STMT_STILL_EXECUTING;
break;
case SQL_NO_DATA:
m_StmtState = STMT_FETCHED_TO_END;
break;
case SQL_ERROR:
if (m_AsyncCanceled == TRUE)
{
m_AsyncCanceled = FALSE;
setDiagRec(DRIVER_ERROR, IDS_S1_008);
}
break;
case SQL_NEED_DATA:
case SQL_INVALID_HANDLE:
default:
break;
}
// Following code is will set it back to original.
if (getODBCAppVersion() == SQL_OV_ODBC2)
{
if (tempMaxRowCnt > 1)
{
temprc = m_AppRowDesc->SetDescField(0, SQL_DESC_ARRAY_SIZE, (SQLPOINTER) tempMaxRowCnt, 0);
if (temprc == SQL_ERROR)
return temprc;
}
}
if(rcCopyData == SQL_ERROR || rc == SQL_ERROR)
return SQL_ERROR;
else if(rcCopyData == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS_WITH_INFO)
return SQL_SUCCESS_WITH_INFO;
else
return rc;
}
SQLRETURN CStmt::SendExtendedFetch(BOOL SkipProcess,
SQLUSMALLINT FetchOrientation,
SQLLEN FetchOffset,
SQLULEN* RowCountPtr,
SQLUSMALLINT* RowStatusArray)
{
SQLRETURN rc = SQL_SUCCESS;
BOOL DispatchFetch = FALSE;
SQLULEN MaxRowCnt;
SQLINTEGER RecLength;
if (m_ConnectHandle->getConnectionStatus() == SQL_CD_TRUE)
{
clearError();
setDiagRec(DRIVER_ERROR, IDS_08_S01, -20005);
return SQL_ERROR;
}
if (m_StmtQueryType == SQL_SELECT_UNIQUE)
{
switch (m_StmtState)
{
case STMT_EXECUTED:
return SQL_SUCCESS;
case STMT_EXECUTED_NO_RESULT:
case STMT_FETCHED:
return SQL_NO_DATA;
default:
break;
}
}
if (! SkipProcess)
{
clearError();
if (m_StmtState == STMT_EXECUTED_NO_RESULT)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
if (m_MaxRows != 0)
{
if (m_RowNumber >= m_MaxRows)
return SQL_NO_DATA;
}
if (m_RowsFetched == -1 || m_RowsFetched == m_CurrentRowFetched)
{
// Calculate the Number of Rows to be fetched
#ifdef _WIN64
m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &MaxRowCnt, SQL_C_UBIGINT, NULL);
#else
m_AppRowDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &MaxRowCnt, SQL_IS_UINTEGER, NULL);
#endif
// Adjust MaxRowCnt to implement MaxRowValues
if (m_MaxRows != 0)
{
if (m_RowNumber + MaxRowCnt > m_MaxRows)
{
MaxRowCnt = m_MaxRows - m_RowNumber;
if (MaxRowCnt == 0)
return SQL_NO_DATA;
}
}
// If MaxRowCnt is more than 1, the application is using Block Cursor
// If MaxRowCnt is 1, the driver tries to do BulkFetch based on SQL_ATTR_CONCURRENCY
if (MaxRowCnt == 1)
{
if (m_Concurrency == SQL_CONCUR_READ_ONLY)
{
RecLength = m_ImpRowDesc->getRecLength();
if (RecLength > 0) // m_FetchBufferSize = 0 is equivalent to BulkFetch is disabled.
if (m_FetchBufferSize > RecLength)
MaxRowCnt = m_FetchBufferSize / RecLength;
if (m_MaxRows != 0)
{
if (m_RowNumber + MaxRowCnt > m_MaxRows)
{
MaxRowCnt = m_MaxRows - m_RowNumber;
if (MaxRowCnt == 0)
return SQL_NO_DATA;
}
}
}
}
m_SrvrCallContext.odbcAPI = SQL_API_SQLEXTENDEDFETCH;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.connectionTimeout = m_ConnectHandle->getConnectionTimeout();
m_SrvrCallContext.u.fetchParams.queryTimeout = m_QueryTimeout;
m_SrvrCallContext.u.fetchParams.stmtLabel = m_StmtLabel;
m_SrvrCallContext.u.fetchParams.maxRowCount = MaxRowCnt;
m_SrvrCallContext.u.fetchParams.maxRowLen = m_MaxLength;
m_SrvrCallContext.u.fetchParams.asyncEnable = m_AsyncEnable;
// Reset the Fetch related member elements
m_RowsFetched = -1;
DispatchFetch = TRUE;
m_ImpRowDesc->setRowsProcessed(0);
m_ImpRowDesc->setDescArrayStatus(MaxRowCnt);
}
else
DispatchFetch = FALSE;
}
if (DispatchFetch)
{
this->m_preFetchThread.setSrvrCallContext(&m_SrvrCallContext);
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if ((m_AsyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendFetch - _beginthreadex()");
rc = SQL_ERROR;
}
ResumeThread(m_AsyncThread);
rc = SQL_STILL_EXECUTING;
Sleep(0);
}
else
{
if ((m_SyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendPrepare - _beginthreadex()");
rc = SQL_ERROR;
}
else
{
ResumeThread(m_SyncThread);
WaitForSingleObject(m_SyncThread,INFINITE);
GetExitCodeThread(m_SyncThread, &m_ThreadStatus);
rc = m_ThreadStatus;
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
}
// rc = ThreadControlProc(&m_SrvrCallContext);
}
}
return rc;
}
SQLRETURN CStmt::ExtendedFetch(SQLUSMALLINT FetchOrientation,
SQLLEN FetchOffset,
SQLULEN* RowCountPtr,
SQLUSMALLINT* RowStatusArray)
{
SQLRETURN rc;
SQLRETURN rcCopyData = SQL_SUCCESS;
BOOL SkipProcess = FALSE;
m_CurrentOdbcAPI = SQL_API_SQLEXTENDEDFETCH;
m_CurrentFetchType = SQL_API_SQLEXTENDEDFETCH;
m_RowStatusArray = RowStatusArray;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
rc = m_ThreadStatus;
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "ExtendedFetch - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
SkipProcess = TRUE;
rc = SendExtendedFetch(SkipProcess,FetchOrientation,FetchOffset,RowCountPtr,RowStatusArray);
}
}
else
rc = SendExtendedFetch(SkipProcess,FetchOrientation,FetchOffset,RowCountPtr,RowStatusArray);
switch (rc)
{
case SQL_SUCCESS:
case SQL_SUCCESS_WITH_INFO:
rcCopyData = m_AppRowDesc->ExtendedCopyData(this, m_NumResultCols, m_ImpRowDesc,
m_RowsFetched, m_CurrentRowFetched, m_RowNumber, m_RowsetSize, RowStatusArray);
if (RowCountPtr != NULL) *RowCountPtr = m_RowsetSize;
m_StmtState = STMT_FETCHED;
m_CurrentRowInRowset = 1;
break;
case SQL_STILL_EXECUTING:
m_StmtState = STMT_STILL_EXECUTING;
break;
case SQL_NO_DATA:
m_StmtState = STMT_FETCHED_TO_END;
break;
case SQL_ERROR:
if (m_AsyncCanceled == TRUE)
{
m_AsyncCanceled = FALSE;
setDiagRec(DRIVER_ERROR, IDS_S1_008);
}
break;
case SQL_NEED_DATA:
case SQL_INVALID_HANDLE:
default:
break;
}
if(rcCopyData == SQL_ERROR || rc == SQL_ERROR)
return SQL_ERROR;
else if(rcCopyData == SQL_SUCCESS_WITH_INFO || rc == SQL_SUCCESS_WITH_INFO)
return SQL_SUCCESS_WITH_INFO;
else
return rc;
}
SQLRETURN CStmt::FetchScroll(SQLUSMALLINT FetchOrientation,
SQLINTEGER FetchOffset)
{
if (FetchOrientation != SQL_FETCH_NEXT)
{
setDiagRec(DRIVER_ERROR, IDS_HY_105);
return SQL_ERROR;
}
return Fetch();
}
SQLRETURN CStmt::GetData(SQLUSMALLINT ColumnNumber,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN *StrLen_or_IndPtr)
{
SQLRETURN rc = SQL_SUCCESS;
unsigned long retCode;
SQLValue_def SQLValue;
unsigned long Index;
unsigned long swapInfoIndex=0;
SQLUSMALLINT *ArrayStatusPtr = NULL;
UCHAR errorMsg[MAX_TRANSLATE_ERROR_MSG_LEN];
SQLINTEGER SQLCharset=0;
SQLSMALLINT SQLDataType=0;
SQLSMALLINT SQLDatetimeCode=0;
SQLINTEGER SQLOctetLength=0;
SQLSMALLINT SQLPrecision=0;
SQLSMALLINT SQLUnsigned=0;
short SQLDataInd=0;
int SQLDataLength=0;
BYTE* SQLDataRow;
BYTE* SQLDataValue;
unsigned long offset=0;
long stmtQueryType = getStmtQueryType();
unsigned long columnIndexCounter=0;
unsigned long indIndex=0;
unsigned long dataIndex=0;
BYTE *IndicatorPtr;
clearError();
m_CurrentOdbcAPI = SQL_API_SQLGETDATA;
if(ColumnNumber > m_NumResultCols)
{
setDiagRec(DRIVER_ERROR, IDS_HY_000, 0, "The value specified for the argument ColumnNumber was greater than the number of columns in the result set.",
"07009", m_CurrentRowInRowset, ColumnNumber);
return SQL_ERROR;
}
if (m_StmtState == STMT_FETCHED_TO_END || m_CurrentRowFetched > m_RowsFetched)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
if (m_CurrentFetchType == SQL_API_SQLFETCH)
rc = m_ImpRowDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, &ArrayStatusPtr,
sizeof(ArrayStatusPtr), NULL);
else if (m_CurrentFetchType == SQL_API_SQLEXTENDEDFETCH)
ArrayStatusPtr = m_RowStatusArray;
if (ArrayStatusPtr != NULL)
{
if (ArrayStatusPtr[m_CurrentRowInRowset] == SQL_ROW_DELETED ||
ArrayStatusPtr[m_CurrentRowInRowset] == SQL_ROW_ERROR)
{
setDiagRec(DRIVER_ERROR, IDS_HY_109);
return SQL_ERROR;
}
}
/*
* In the case of fetch returning no data plus warnings, the application could potentially
* call getdata - handle this condition here
*/
if (m_RowsFetched == 0)
return SQL_NO_DATA;
Index = (m_CurrentRowFetched -1 - m_RowsetSize + m_CurrentRowInRowset ) * m_NumResultCols + ColumnNumber -1;
swapInfoIndex = m_CurrentRowFetched -1 - m_RowsetSize + m_CurrentRowInRowset;
if (Index >= m_FetchDataValue.numberOfElements)
{
setDiagRec(DRIVER_ERROR, IDS_HY_000, 0, NULL, NULL,
m_CurrentRowInRowset, ColumnNumber);
return SQL_ERROR;
}
SQLDataRow = (BYTE*)m_FetchDataValue.rowAddress[m_CurrentRowFetched -1 - m_RowsetSize + m_CurrentRowInRowset];
offset = 0;
SQLDataValue = 0;
if(!getFetchCatalog()) // if (stmtQueryType == 10000)
{
BOOL byteSwap = getByteSwap();
SQLDataInd = 0;
columnIndexCounter = (ColumnNumber-1)*2;
getImpBulkSQLData(ColumnNumber, SQLCharset, SQLDataType, SQLDatetimeCode, SQLOctetLength, SQLPrecision,SQLUnsigned);
if ((indIndex=m_ColumnIndexes[columnIndexCounter]) != -1)
{
IndicatorPtr = SQLDataRow + indIndex;
}
else
IndicatorPtr = NULL;
dataIndex = m_ColumnIndexes[++columnIndexCounter];
SQLDataValue = SQLDataRow + dataIndex;
if ((IndicatorPtr == NULL) || (IndicatorPtr != NULL && *((short *)IndicatorPtr) != -1))
{
// Swapping is done only once, the first time. The returnedLength() function prevents
// additional swap of column values incase data is returned by multiple calls of GetData().
// m_SwapInfo information can not be used for this purpose because 1, it keeps track only
// row level swap information 2, it contains useful values only when the application had
// called SQLBindCol() before (a SQLFetch() and) SQLGetData(). Note that the problem does
// happen with Catalog APIs where we are still getting the data in column-wise format.
//if ((byteSwap) && (m_ImpRowDesc->returnedLength(ColumnNumber) == 0) && (m_SwapInfo[swapInfoIndex] == 'N'))
int returnedLength = m_ImpRowDesc->returnedLength(ColumnNumber);
if ((byteSwap) && (returnedLength == 0) && (m_SwapInfo[m_CurrentRowFetched - 1][ColumnNumber - 1] == 'N'))
SQLDatatype_Dependent_Swap(SQLDataValue, SQLDataType, SQLCharset, SQLOctetLength, SQLDatetimeCode);
SQLDataLength = SQLOctetLength;
}
else
{
SQLDataValue = 0;
SQLDataLength = 0;
SQLDataInd = -1;
}
if (SQLDataInd != -1 && SQLCharset != SQLCHARSETCODE_UCS2 &&
((SQLDataType == SQLTYPECODE_CHAR) || (SQLDataType == SQLTYPECODE_BIT) || (SQLDataType == SQLTYPECODE_VARCHAR)))
SQLDataLength++;
if(m_MaxLength > 0)
{
switch (SQLDataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
{
bool increment = false;
if (m_MaxLength > 0)
{
if (SQLDataLength - 1 > m_MaxLength)
{
SQLDataLength = m_MaxLength + 1;
increment = true;
}
}
if (SQLDataInd != -1 && !increment)
SQLDataLength++;
}
break;
case SQLTYPECODE_VARCHAR_WITH_LENGTH:
case SQLTYPECODE_VARCHAR_LONG:
case SQLTYPECODE_BITVAR:
{
if (m_MaxLength > 0 && SQLDataValue != NULL)
{
SQLDataLength = *(USHORT *)SQLDataValue;
if (SQLDataLength > m_MaxLength)
*(USHORT *)SQLDataValue = m_MaxLength;
//SQLDataLength-3 to account for length(2 bytes) and null terminator(1 byte)
//SQLDataLength = ((SQLDataLength-3)>maxLength)?maxLength + 3:SQLDataLength;
//*(USHORT *)SQLDataValue = SQLDataLength - 3;
break;
}
}
break;
}
} // if (m_MaxLength > 0)
SQLValue.dataType = SQLDataType;
SQLValue.dataInd = SQLDataInd;
SQLValue.dataCharset = SQLCharset;
SQLValue.dataValue._length = SQLDataLength;
SQLValue.dataValue._buffer = SQLDataValue;
}
else
{
for (int ColumnCount=0; ColumnCount < ColumnNumber; ColumnCount++)
{
SQLDataValue = SQLDataRow;
SQLDataInd = (short)*(unsigned char*)(SQLDataValue);
if (SQLDataInd == 0)
{
getImpSQLData(ColumnCount+1, SQLCharset, SQLDataType, SQLDatetimeCode, SQLOctetLength, SQLPrecision,SQLUnsigned);
SQLDataValue = SQLDataValue + 1;
SQLDataLength = dataLengthFetchPerf(SQLDataType, SQLOctetLength, getMaxLength(), SQLCharset, SQLDataValue);
SQLDataRow = SQLDataRow + 1 + SQLDataLength;
}
else
{
SQLDataValue = 0;
SQLDataLength = 0;
SQLDataInd = -1;
SQLDataRow = SQLDataRow + 1;
}
}
if (getAPIDecision() && !getFetchCatalog())
switch (SQLDataType)
{
case SQLTYPECODE_CHAR:
case SQLTYPECODE_BIT:
case SQLTYPECODE_VARCHAR:
if (SQLDataInd != -1) SQLDataLength++;
break;
}
SQLValue.dataType = SQLDataType;
SQLValue.dataInd = SQLDataInd;
SQLValue.dataCharset = SQLCharset;
SQLValue.dataValue._length = SQLDataLength;
SQLValue.dataValue._buffer = SQLDataValue;
}
retCode = m_ImpRowDesc->GetData(&SQLValue, ColumnNumber,
TargetType, TargetValuePtr, BufferLength, StrLen_or_IndPtr,
errorMsg, sizeof(errorMsg), m_bFetchCatalog);
if (retCode != SQL_SUCCESS && retCode != SQL_NO_DATA)
{
if (errorMsg[0] != '\0')
setDiagRec(DRIVER_ERROR, retCode, 0, (char *)errorMsg, NULL, m_CurrentRowFetched, ColumnNumber);
else
setDiagRec(DRIVER_ERROR, retCode, 0, NULL, NULL, m_CurrentRowInRowset, ColumnNumber);
switch (retCode)
{
case IDS_01_004:
case IDS_01_S07:
case IDS_22_003:
case IDS_186_DSTODRV_TRUNC:
rc = SQL_SUCCESS_WITH_INFO;
break;
default:
rc = SQL_ERROR;
}
}
else
rc = retCode;
return rc;
}
SQLRETURN CStmt::SetPos(SQLUSMALLINT RowNumber,
SQLUSMALLINT Operation,
SQLUSMALLINT LockType)
{
SQLRETURN rc = SQL_SUCCESS;
SQLUSMALLINT *ArrayStatusPtr = NULL;
clearError();
m_CurrentOdbcAPI = SQL_API_SQLSETPOS;
switch (Operation)
{
case SQL_POSITION:
if (m_StmtState == STMT_EXECUTED || m_StmtState == STMT_FETCHED_TO_END)
{
setDiagRec(DRIVER_ERROR, IDS_24_000);
return SQL_ERROR;
}
if (RowNumber == 0 || RowNumber > m_RowsetSize)
{
setDiagRec(DRIVER_ERROR, IDS_HY_107);
return SQL_ERROR;
}
if (m_CurrentFetchType == SQL_API_SQLFETCH)
rc = m_ImpRowDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, &ArrayStatusPtr,
sizeof(ArrayStatusPtr), NULL);
else if (m_CurrentFetchType == SQL_API_SQLEXTENDEDFETCH)
ArrayStatusPtr = m_RowStatusArray;
if (ArrayStatusPtr != NULL)
{
if (ArrayStatusPtr[RowNumber] == SQL_ROW_DELETED ||
ArrayStatusPtr[RowNumber] == SQL_ROW_ERROR)
{
setDiagRec(DRIVER_ERROR, IDS_HY_109);
return SQL_ERROR;
}
}
m_CurrentRowInRowset = RowNumber;
m_ImpRowDesc->SetPos(m_NumResultCols);
break;
default:
setDiagRec(DRIVER_ERROR, IDS_HY_C00);
break;
}
return rc;
}
long CStmt::getImpDescCount(){ return m_ImpRowDesc->getDescCount();}
BOOL CStmt::getImpSQLData(long colnumber,
SQLINTEGER& SQLCharset, SQLSMALLINT& SQLDataType,
SQLSMALLINT& SQLDatetimeCode, SQLINTEGER& SQLOctetLength,
SQLSMALLINT& SQLPrecision, SQLSMALLINT& SQLUnsigned)
{
return m_ImpRowDesc->getDescRecSQLData(colnumber,
SQLCharset, SQLDataType,
SQLDatetimeCode, SQLOctetLength,
SQLPrecision, SQLUnsigned);
}
BOOL CStmt::getImpBulkSQLData(long colnumber,
SQLINTEGER& SQLCharset, SQLSMALLINT& SQLDataType,
SQLSMALLINT& SQLDatetimeCode, SQLINTEGER& SQLOctetLength,
SQLSMALLINT& SQLPrecision, SQLSMALLINT& SQLUnsigned)
{
BOOL rc = m_ImpRowDesc->getDescRecSQLData(colnumber,
SQLCharset, SQLDataType,
SQLDatetimeCode, SQLOctetLength,
SQLPrecision, SQLUnsigned);
if (SQLDataType == SQL_CHAR)
SQLOctetLength = SQLOctetLength -1;
return rc;
}
long CStmt::getImpRowDescCount(){ return m_ImpRowDesc->getDescCount();}
BOOL CStmt::getImpRowData(long colnumber,
SQLINTEGER& SQLCharset, SQLSMALLINT& SQLDataType,
SQLSMALLINT& SQLDatetimeCode, SQLINTEGER& SQLMaxLength,
SQLSMALLINT& SQLPrecision, SQLSMALLINT& SQLUnsigned,
SQLSMALLINT& SQLNullable)
{
return m_ImpRowDesc->getDescRowRecData(colnumber,
SQLCharset, SQLDataType,
SQLDatetimeCode, SQLMaxLength,
SQLPrecision, SQLUnsigned,
SQLNullable);
}
BOOL CStmt::getImpRowData(long colnumber, SQLSMALLINT& SQLDataType,
SQLINTEGER& SQLMaxLength, SQLSMALLINT& SQLNullable)
{
return m_ImpRowDesc->getDescRowRecData(colnumber,
SQLDataType, SQLMaxLength, SQLNullable);
}
long CStmt::getImpParamDescCount(){ return m_ImpParamDesc->getDescCount();}
BOOL CStmt::getImpParamData(long colnumber,
SQLINTEGER& SQLCharset, SQLSMALLINT& SQLDataType,
SQLSMALLINT& SQLDatetimeCode, SQLINTEGER& SQLMaxLength,
SQLSMALLINT& SQLPrecision, SQLSMALLINT& SQLUnsigned,
SQLSMALLINT& SQLNullable)
{
return m_ImpParamDesc->getDescParamRecData(colnumber,
SQLCharset, SQLDataType,
SQLDatetimeCode, SQLMaxLength,
SQLPrecision, SQLUnsigned,
SQLNullable);
}
BOOL CStmt::checkInputParam(string SqlString)
{
char del;
char ch;
int state = 0;
unsigned int size = SqlString.size();
for (unsigned int i=0; i < size; i++)
{
ch = SqlString[i];
switch (state)
{
case 0:
if (ch == '?' ) return TRUE;
else if (ch == '\'' || ch == '"' ) { state = 1; del = ch; }
break;
case 1:
if (ch == del ) { state = 2; }
break;
case 2:
if (ch == del ) { state = 1; }
else { i--; state = 0; }
break;
}
}
return FALSE;
}
bool CStmt::isInfoStats(char *inpString)
{
bool result = false;
char *ptr = inpString;
while (*ptr != '\0' && isspace(*ptr))
ptr++;
if (_strnicmp(ptr, "INFOSTATS", 9) == 0)
result = true;
return result;
}
// Passing TRUE for padDelimitedIdentifiers while substitute 'X' as character for all delimited identifiers. So that in POSITIONED
// UPDATE/DELETE for a table can be searched easily for "WHERE CURRENT OF" string.
void CStmt::trimSqlString(unsigned char* inpString, unsigned char* outString, unsigned long& sqlStringLen, BOOL padDelimitedIdentifiers)
{
char del;
char ch;
int state = 0;
BOOL blank_added = FALSE;
BOOL copy = FALSE;
unsigned long len = 0;
if (isInfoStats((char *)inpString))
{
strncpy((char *)outString, (const char *)inpString, sqlStringLen);
outString[sqlStringLen] = '\0';
return;
}
for (unsigned long i=0; i < sqlStringLen; i++)
{
ch = inpString[i];
copy = TRUE;
switch (state)
{
case 0:
if (ch == '\'' || ch == '"' ) { state = 1; del = ch; blank_added = FALSE; }
//else if (isspace(ch))
else if ((ch) == ' ' || (ch) == '\t')
{
if (blank_added == FALSE)
{
blank_added = TRUE;
ch = ' ';
}
else
copy = FALSE;
}
else if (blank_added)
blank_added = FALSE;
break;
case 1:
if (ch == del ) { state = 2; }
if (padDelimitedIdentifiers)
ch = 'X';
break;
case 2:
if (ch == del ) { state = 1; }
else { i--; state = 0; copy = FALSE;}
if (padDelimitedIdentifiers)
ch = 'X';
break;
}
if (copy)
{
if ( state == 0)
outString[len++] = toupper(ch);
else
outString[len++] = ch;
}
}
if (outString[len-1] == ' ')
outString[--len] = '\0';
else
outString[len] = '\0';
sqlStringLen = len;
}
void CStmt::setNumberOfElements(unsigned long count)
{
m_FetchDataValue.numberOfElements = count;
}
unsigned long CStmt::getNumberOfElements(void)
{
return m_FetchDataValue.numberOfElements;
}
void CStmt::setNumberOfRows(unsigned long count)
{
m_FetchDataValue.numberOfRows = count;
}
unsigned long CStmt::getNumberOfRows(void)
{
return m_FetchDataValue.numberOfRows;
}
void CStmt::setRowAddress( unsigned long row, BYTE* address)
{
if (row <= m_FetchDataValue.numberOfRows)
m_FetchDataValue.rowAddress[row] = (LONG_PTR)address;
}
BYTE* CStmt::getRowAddress( unsigned long row)
{
if (row <= m_FetchDataValue.numberOfRows)
return (unsigned char*)m_FetchDataValue.rowAddress[row];
else
return 0;
}
void CStmt::clearFetchDataValue(void)
{
if (m_outputDataValue._length != 0 &&
m_outputDataValue._buffer != NULL)
delete m_outputDataValue._buffer;
m_outputDataValue._length = 0;
m_outputDataValue._buffer = NULL;
if (m_FetchDataValue.rowAddress != NULL)
delete[] m_FetchDataValue.rowAddress;
m_FetchDataValue.numberOfElements = 0;
m_FetchDataValue.numberOfRows = 0;
m_FetchDataValue.rowAddress = NULL;
if (m_ColumnIndexes != NULL)
{
delete[] m_ColumnIndexes;
m_ColumnIndexes = NULL;
}
if (m_SwapInfo != NULL)
{
for (int r = 0; r < m_SwapInfo_NumRows; r++)
{
if (m_SwapInfo[r] != NULL)
delete[] (m_SwapInfo[r]);
}
delete[] m_SwapInfo;
m_SwapInfo = NULL;
m_SwapInfo_NumRows = 0;
}
}
void CStmt::clearInputValueList(void)
{
if (m_InputValueList._buffer != NULL)
delete m_InputValueList._buffer;
m_InputValueList._buffer = 0;
m_InputValueList._length = 0;
}
SQLRETURN CStmt::mapSqlRowIdsToDrvrRowIds(BYTE *&WarningOrError)
{
SQLULEN AppArrayStatusSize;
IDL_long sqlRowId = -1, drvrRowId = -1; //sql row id starts counting at 1, not 0
unsigned char *curptr = (unsigned char*)WarningOrError;
long msg_total_len = 0;
IDL_long numConditions = 0;
IDL_long errorTextLen = 0;
int i;
if (curptr == NULL)
return SQL_ERROR;
numConditions = *(IDL_long*)(curptr+msg_total_len);
msg_total_len +=4;
if (numConditions > 0)
{
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &AppArrayStatusSize, SQL_IS_UINTEGER, NULL);
for (i = 0; i < numConditions; i++)
{
sqlRowId= *(IDL_long*)(curptr+msg_total_len);
if (AppArrayStatusSize > sqlRowId && sqlRowId > 0)
{
//find trueRowId
drvrRowId = m_RowIdMap[sqlRowId-1];
memcpy(curptr+msg_total_len,&drvrRowId,sizeof(IDL_long));
}
msg_total_len +=4; //move past rowId
msg_total_len +=4; //move past sqlCode
errorTextLen= *(IDL_long*)(curptr+msg_total_len);
msg_total_len +=4; //move past errorTextLen
msg_total_len +=errorTextLen;
msg_total_len += 6 * (sizeof(char));//sizeof(sqlState);
}
}
return SQL_SUCCESS;
}
// For Stored Proceudre Call support
SQLRETURN CStmt::setExecuteCallOutputs()
{
m_AppParamDesc->CopyData(this, m_NumResultCols, m_ImpParamDesc,
m_RowsFetched, m_CurrentRowFetched, m_RowNumber, m_RowsetSize);
return SQL_SUCCESS;
}
// for tcpip transport
CTCPIPSystemDrvr* CStmt::getSrvrTCPIPSystem()
{
return m_ConnectHandle->m_srvrTCPIPSystem;
}
// obsolete - get rid of it once the collapsed driver goes away for genus
void CStmt::setRowsetArrayStatus(const ERROR_DESC_LIST_def *sqlWarning, long rowsAffected)
{
SQLUINTEGER AppArrayStatusPtr;
SQLUINTEGER AppArrayStatusSize;
ERROR_DESC_def *_buffer;
IDL_long rowId;
unsigned long i,count;
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &AppArrayStatusSize, SQL_IS_UINTEGER, NULL);
m_ImpParamDesc->GetDescField(0, SQL_DESC_ROWS_PROCESSED_PTR, &AppArrayStatusPtr, SQL_IS_UINTEGER, NULL);
if (AppArrayStatusPtr == NULL)
return;
if (rowsAffected == -1)
{
m_ImpParamDesc->setDescArrayStatus(AppArrayStatusSize, SQL_PARAM_ERROR);
return;
}
else
m_ImpParamDesc->setDescArrayStatus(AppArrayStatusSize, SQL_PARAM_SUCCESS);
if (rowsAffected == AppArrayStatusSize)
return;
for (i=0; i < sqlWarning->_length; i++)
{
_buffer = sqlWarning->_buffer + i;
rowId = _buffer->rowId - 1;
if (rowId > AppArrayStatusSize) break;
if (rowId < 0) continue;
m_ImpParamDesc->setDescArrayStatusAt(rowId, SQL_PARAM_ERROR);
}
for (i=0,count=1; i <AppArrayStatusSize; i++)
{
if (m_ImpParamDesc->getDescArrayStatusFrom(i) == SQL_PARAM_SUCCESS)
{
if (count++ > rowsAffected)
{
m_ImpParamDesc->setDescArrayStatusAt(i, SQL_PARAM_ERROR);
setDiagRec(SERVER_ERROR, IDS_SQL_ERROR, 0, NULL, NULL, i+1);
continue;
}
}
}
}
void CStmt::setRowsetArrayStatus(BYTE *&WarningOrError, long rowsAffected)
{
SQLULEN AppArrayStatusPtr;
SQLULEN AppArrayStatusSize;
long msg_total_len = 0;
long numConditions = 0;
char sqlState[6];
long errorTextLen = 0;
long rowId = 0;
sqlState[0] = '\0';
unsigned char *curptr;
int i;
#ifdef _WIN64
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &AppArrayStatusSize, SQL_IS_POINTER, NULL);
m_ImpParamDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, &AppArrayStatusPtr, SQL_C_UBIGINT, NULL);
#else
m_AppParamDesc->GetDescField(0, SQL_DESC_ARRAY_SIZE, &AppArrayStatusSize, SQL_IS_UINTEGER, NULL);
m_ImpParamDesc->GetDescField(0, SQL_DESC_ARRAY_STATUS_PTR, &AppArrayStatusPtr, SQL_IS_UINTEGER, NULL);
#endif
if (AppArrayStatusPtr == NULL)
return;
if (rowsAffected == -1)
{
m_ImpParamDesc->setDescArrayStatus(AppArrayStatusSize, SQL_PARAM_ERROR);
return;
}
if (rowsAffected == AppArrayStatusSize)
return;
curptr = (unsigned char *)WarningOrError;
if (curptr == NULL)
return;
numConditions = *(IDL_long*)(curptr+msg_total_len);
msg_total_len +=4;
if (numConditions > 0)
{
for (i = 0; i < numConditions; i++)
{
rowId= *(IDL_long*)(curptr+msg_total_len);
msg_total_len +=4; //move past rowId
msg_total_len +=4; //move past sqlCode
errorTextLen= *(IDL_long*)(curptr+msg_total_len);
msg_total_len +=4; //move past errorTextLen
msg_total_len +=errorTextLen;
msg_total_len +=sizeof(sqlState);
rowId = rowId -1; // RowId index starts from 0
if (rowId > AppArrayStatusSize) break;
if (rowId < 0) continue;
m_ImpParamDesc->setDescArrayStatusAt(rowId, SQL_PARAM_ERROR);
}
}
} /* setRowsetArrayStatus() */
void CStmt::setColumnOffset(short columnNumber, long offset)
{
long totalLength = m_outputDataValue._length;
long columnOffset = sizeof(long) * (columnNumber - 1);
totalLength = ((totalLength + 4 - 1) >> 2) << 2;
*(long*)(&m_outputDataValue._buffer[totalLength + columnOffset]) = offset;
}
long CStmt::getColumnOffset(short columnNumber)
{
long totalLength = m_outputDataValue._length;
long columnOffset = sizeof(long) * (columnNumber - 1);
totalLength = ((totalLength + 4 - 1) >> 2) << 2;
return *(long*)(&m_outputDataValue._buffer[totalLength + columnOffset]);
}
SQLRETURN CStmt::SendExtractLob(IDL_short extractType,
IDL_string lobHandle,
IDL_long lobHandleLen,
IDL_long &extractLen,
BYTE * &extractData)
{
SQLRETURN rc = SQL_SUCCESS;
m_SrvrCallContext.odbcAPI = SRVR_API_EXTRACTLOB;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.connectionTimeout = m_ConnectHandle->getConnectionTimeout();
m_SrvrCallContext.u.fetchParams.queryTimeout = m_QueryTimeout;
m_SrvrCallContext.u.extractLobParams.extractType = extractType;
m_SrvrCallContext.u.extractLobParams.lobHandle = lobHandle;
m_SrvrCallContext.u.extractLobParams.lobHandleLen = lobHandleLen;
m_SrvrCallContext.u.extractLobParams.extractLen = extractLen;
m_SrvrCallContext.u.extractLobParams.extractData = extractData;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if ((m_AsyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendExtractLob - _beginthreadex()");
rc = SQL_ERROR;
}
ResumeThread(m_AsyncThread);
rc = SQL_STILL_EXECUTING;
Sleep(0);
}
else
{
if ((m_SyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendExtractLob - _beginthreadex()");
rc = SQL_ERROR;
}
else
{
ResumeThread(m_SyncThread);
WaitForSingleObject(m_SyncThread, INFINITE);
GetExitCodeThread(m_SyncThread, &m_ThreadStatus);
rc = m_ThreadStatus;
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
}
}
if (rc == SQL_SUCCESS)
{
extractLen = m_SrvrCallContext.u.extractLobParams.extractLen;
extractData = m_SrvrCallContext.u.extractLobParams.extractData;
if (m_ConnectHandle->lobHandleSave != NULL)
free(m_ConnectHandle->lobHandleSave);
m_ConnectHandle->lobHandleSave = (IDL_string)malloc(lobHandleLen);
memcpy(m_ConnectHandle->lobHandleSave, lobHandle, lobHandleLen);
m_ConnectHandle->lobHandleLenSave = lobHandleLen;
}
return rc;
}
SQLRETURN CStmt::ExtractLob(IDL_short extractType,
IDL_string lobHandle,
IDL_long lobHandleLen,
IDL_long &extractLen,
BYTE * &extractData)
{
SQLRETURN rc = SQL_SUCCESS;
BOOL SkipProcess = FALSE;
m_CurrentOdbcAPI = SRVR_API_EXTRACTLOB;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
rc = m_ThreadStatus;
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "Fetch - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
SkipProcess = TRUE;
rc = SendExtractLob(extractType, lobHandle, lobHandleLen, extractLen, extractData);
}
}
else
rc = SendExtractLob(extractType, lobHandle, lobHandleLen, extractLen, extractData);
return rc;
}
SQLRETURN CStmt::SendUpdateLob(IDL_long updateType,
IDL_string lobHandle,
IDL_long lobHandleLen,
IDL_long_long totalLength,
IDL_long_long offset,
IDL_long_long pos,
IDL_long_long length,
BYTE * data)
{
SQLRETURN rc = SQL_SUCCESS;
m_SrvrCallContext.odbcAPI = SRVR_API_UPDATELOB;
m_SrvrCallContext.sqlHandle = this;
m_SrvrCallContext.SQLSvc_ObjRef = m_ConnectHandle->getSrvrObjRef();
m_SrvrCallContext.ASSvc_ObjRef = NULL;
m_SrvrCallContext.eventHandle = m_StmtEvent;
m_SrvrCallContext.dialogueId = m_ConnectHandle->getDialogueId();
m_SrvrCallContext.connectionTimeout = m_ConnectHandle->getConnectionTimeout();
m_SrvrCallContext.u.fetchParams.queryTimeout = m_QueryTimeout;
m_SrvrCallContext.u.updateLobParams.updateType = updateType;
m_SrvrCallContext.u.updateLobParams.lobHandle = lobHandle;
m_SrvrCallContext.u.updateLobParams.lobHandleLen = lobHandleLen;
m_SrvrCallContext.u.updateLobParams.totalLength = totalLength;
m_SrvrCallContext.u.updateLobParams.offset = offset;
m_SrvrCallContext.u.updateLobParams.pos = pos;
m_SrvrCallContext.u.updateLobParams.length = length;
m_SrvrCallContext.u.updateLobParams.data = data;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if ((m_AsyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendExtractLob - _beginthreadex()");
rc = SQL_ERROR;
}
ResumeThread(m_AsyncThread);
rc = SQL_STILL_EXECUTING;
Sleep(0);
}
else
{
if ((m_SyncThread = (HANDLE)_beginthreadex(NULL, 0, ThreadControlProc,
&m_SrvrCallContext, CREATE_SUSPENDED, &m_ThreadAddr)) == 0)
{
setNTError(m_ConnectHandle->getErrorMsgLang(), "SendExtractLob - _beginthreadex()");
rc = SQL_ERROR;
}
else
{
ResumeThread(m_SyncThread);
WaitForSingleObject(m_SyncThread, INFINITE);
GetExitCodeThread(m_SyncThread, &m_ThreadStatus);
rc = m_ThreadStatus;
CloseHandle(m_SyncThread);
m_SyncThread = NULL;
}
}
return rc;
}
SQLRETURN CStmt::UpdateLob(IDL_long updateType,
IDL_string lobHandle,
IDL_long lobHandleLen,
IDL_long_long totalLength,
IDL_long_long offset,
IDL_long_long pos,
IDL_long_long length,
BYTE * data)
{
SQLRETURN rc = SQL_SUCCESS;
BOOL SkipProcess = FALSE;
if (m_AsyncEnable == SQL_ASYNC_ENABLE_ON)
{
if (m_AsyncThread != NULL)
{
if (GetExitCodeThread(m_AsyncThread, &m_ThreadStatus))
{
if (m_ThreadStatus == STILL_ACTIVE)
rc = SQL_STILL_EXECUTING;
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
if (m_AsyncCanceled == TRUE)
rc = SQL_ERROR;
else
rc = m_ThreadStatus;
}
}
else
{
CloseHandle(m_AsyncThread);
m_AsyncThread = NULL;
setNTError(m_ConnectHandle->getErrorMsgLang(), "Fetch - GetExitCodeThread()");
rc = SQL_ERROR;
}
}
else
{
if (m_ThreadStatus == SQL_STILL_EXECUTING)
SkipProcess = TRUE;
rc = SendUpdateLob(updateType, lobHandle, lobHandleLen, totalLength, offset, pos, length, data);
}
}
else
rc = SendUpdateLob(updateType, lobHandle, lobHandleLen, totalLength, offset, pos, length, data);
return rc;
}