Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2709 lines
66 KiB

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_DB_SEG
#pragma code_seg(AFX_DB_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// CDBByteArray db specific class for holding byte array data
class CDBByteArray : public CByteArray
{
DECLARE_DYNAMIC(CDBByteArray)
// Operations
void SetLength(int nNewSize);
};
inline void CDBByteArray::SetLength(int nNewSize)
{
// Can't grow buffer since ODBC has been SQLBindCol'd on it.
ASSERT(nNewSize <= m_nMaxSize);
m_nSize = nNewSize;
}
//////////////////////////////////////////////////////////////////////////////
// CFieldExchange
CFieldExchange::CFieldExchange(UINT nOperation, CRecordset* prs, void* pvField)
{
ASSERT(nOperation >= BindParam && nOperation <= DumpField);
ASSERT_VALID(prs);
ASSERT(prs->m_hstmt != SQL_NULL_HSTMT);
m_nFieldType = noFieldType;
m_nOperation = nOperation;
m_prs = prs;
m_pvField = pvField;
m_nFields = 0;
m_nParams = 0;
m_nParamFields = 0;
m_bField = FALSE;
m_pstr = NULL;
m_hstmt = SQL_NULL_HSTMT;
m_lDefaultLBFetchSize = 0x00010000;
m_lDefaultLBReallocSize = 0x00010000;
}
BOOL CFieldExchange::IsFieldType(UINT* pnField)
{
if (m_nFieldType == outputColumn)
{
*pnField = ++m_nFields;
// Recordset's m_nFields must match number of Fields!
ASSERT(m_nFields <= m_prs->m_nFields);
}
else
{
// Make sure SetFieldType was called
ASSERT(m_nFieldType == inputParam ||
m_nFieldType == outputParam ||
m_nFieldType == inoutParam);
*pnField = ++m_nParams;
// Recordset's m_nParams must match number of Params!
ASSERT(m_nParams <= m_prs->m_nParams);
}
if (m_nOperation == BindParam || m_nOperation == RebindParam)
{
// only valid on a param field type
return m_nFieldType != outputColumn;
}
else
{
// valid only on an outputColumn field type
return m_nFieldType == outputColumn;
}
}
// Default implementation for RFX functions
void CFieldExchange::Default(LPCTSTR szName,
void* pv, LONG* plLength, int nCType, UINT cbValue, UINT cbPrecision)
{
RETCODE nRetCode;
UINT nField = (m_nFieldType == outputColumn)? m_nFields: m_nParams;
switch (m_nOperation)
{
case BindParam:
if (m_prs->IsParamStatusNull(nField - 1))
*plLength = SQL_NULL_DATA;
else
*plLength = cbValue;
// For params, CType is same as SQL type
AFX_SQL_SYNC(::SQLBindParameter(m_hstmt, (UWORD)nField,
m_nFieldType, (SWORD)nCType, (SWORD)nCType, cbPrecision, 0,
pv, 0, plLength));
if (nRetCode != SQL_SUCCESS)
m_prs->ThrowDBException(nRetCode, m_hstmt);
// Add the member address to the param map
m_prs->m_mapParamIndex.SetAt(pv, (void*)nField);
return;
case RebindParam:
// Only need for date/time parameters and UNICODE text
return;
case BindFieldForUpdate:
if (!m_prs->IsFieldStatusDirty(nField - 1))
{
// If not dirty, set length to SQL_IGNORE for SQLSetPos updates
*plLength = SQL_IGNORE;
}
else if (!m_prs->IsFieldStatusNull(nField - 1))
{
// Reset the length as it may have changed for var length fields
*plLength = cbValue;
}
return;
case UnbindFieldForUpdate:
// Reset bound length to actual length to clear SQL_IGNOREs
if (!m_prs->IsFieldStatusDirty(nField - 1))
*plLength = cbValue;
return;
case BindFieldToColumn:
AFX_SQL_SYNC(::SQLBindCol(m_prs->m_hstmt, (UWORD)nField, (SWORD)nCType,
pv, cbValue, plLength));
if (!m_prs->Check(nRetCode))
m_prs->ThrowDBException(nRetCode);
// Add the member address to the field map
m_prs->m_mapFieldIndex.SetAt(pv, (void*)nField);
return;
case Name:
if (m_prs->IsFieldStatusDirty(nField - 1))
{
// We require a name
ASSERT(lstrlen(szName) != 0);
*m_pstr += szName;
*m_pstr += m_lpszSeparator;
}
return;
case NameValue:
if (m_prs->IsFieldStatusDirty(nField - 1))
{
*m_pstr += szName;
*m_pstr += '=';
}
// Fall through
case Value:
if (m_prs->IsFieldStatusDirty(nField - 1))
{
// If user marked column NULL, reflect this in length
if (m_prs->IsFieldStatusNull(nField - 1))
*plLength = SQL_NULL_DATA;
else
*plLength = cbValue;
// If optimizing for bulk add, only need lengths set correctly
if(!(m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
{
*m_pstr += '?';
*m_pstr += m_lpszSeparator;
m_nParamFields++;
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&m_prs->m_rgODBCFieldInfos[nField - 1];
AFX_SQL_SYNC(::SQLBindParameter(m_hstmt,
(UWORD)m_nParamFields, SQL_PARAM_INPUT,
(SWORD)nCType, pODBCInfo->m_nSQLType,
pODBCInfo->m_nPrecision, pODBCInfo->m_nScale,
pv, 0, plLength));
if (nRetCode != SQL_SUCCESS)
m_prs->ThrowDBException(nRetCode, m_hstmt);
}
}
return;
case MarkForUpdate:
{
// Get the field data
CFieldInfo* pInfo = &m_prs->m_rgFieldInfos[nField - 1];
// If user changed field value from previous value, mark field dirty
if ((pInfo->m_bStatus & AFX_SQL_FIELD_FLAG_NULL))
{
if (!m_prs->IsFieldStatusNull(nField - 1))
m_prs->SetDirtyFieldStatus(nField - 1);
}
else
{
// Saved field is not NULL. current field null, so field dirty
BOOL bDirty = m_prs->IsFieldStatusNull(nField - 1);
// If values differ, then field dirty
void* pvDataCache;
if (pInfo->m_nDataType == AFX_RFX_BOOL ||
pInfo->m_nDataType == AFX_RFX_BYTE ||
pInfo->m_nDataType == AFX_RFX_INT ||
pInfo->m_nDataType == AFX_RFX_LONG ||
pInfo->m_nDataType == AFX_RFX_SINGLE)
{
// If caching data by value, pass a ref
pvDataCache = &pInfo->m_pvDataCache;
}
else
pvDataCache = pInfo->m_pvDataCache;
if (bDirty || !AfxCompareValueByRef(pv, pvDataCache, pInfo->m_nDataType))
m_prs->SetDirtyFieldStatus(nField - 1);
}
#ifdef _DEBUG
// Field address must not change - ODBC's SQLBindCol depends upon this
void* pvBind;
switch (pInfo->m_nDataType)
{
default:
pvBind = pv;
break;
case AFX_RFX_TEXT:
#ifdef _UNICODE
pvBind = m_prs->m_pvFieldProxy[nField-1];
#else // !_UNICODE
{
pvBind = ((CString*)pv)->GetBuffer(0);
((CString*)pv)->ReleaseBuffer();
}
#endif
break;
case AFX_RFX_DATE:
pvBind = m_prs->m_pvFieldProxy[nField-1];
break;
}
if (pInfo->m_pvBindAddress != pvBind)
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
if ((m_pvField == NULL || m_pvField == pv) &&
m_prs->IsFieldStatusDirty(nField - 1))
{
m_bField = TRUE;
}
}
return;
case StoreField:
AfxStoreField(*m_prs, nField, pv);
return;
case LoadField:
AfxLoadField(*m_prs, nField, pv, plLength);
return;
default:
ASSERT(FALSE);
}
}
// Note: CString.m_pchData must not be changed. This address is registered
// with ODBC and must remain valid until the recordset is released.
void AFXAPI RFX_Text(CFieldExchange* pFX, LPCTSTR szName,
CString& value, int nMaxLength, int nColumnType, short nScale)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
ASSERT(AfxIsValidAddress(&value, sizeof(CString)));
RETCODE nRetCode;
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
default:
pFX->Default(szName, value.GetBuffer(0), plLength,
SQL_C_CHAR, value.GetLength(), nMaxLength);
value.ReleaseBuffer();
return;
case CFieldExchange::BindParam:
{
// Preallocate to nMaxLength and setup binding address
value.GetBufferSetLength(nMaxLength);
void* pvParam = value.LockBuffer(); // will be overwritten if UNICODE
#ifdef _UNICODE
// Must use proxy to translate unicode data into non-unicode param
pFX->m_prs->m_bRebindParams = TRUE;
// Allocate proxy array if necessary
if (pFX->m_prs->m_pvParamProxy == NULL)
{
pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
memset(pFX->m_prs->m_pvParamProxy, 0,
pFX->m_prs->m_nParams*sizeof(void*));
pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
}
// Allocate non-unicode string to nMaxLength if necessary for SQLBindParameter
if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
{
pvParam = new CHAR[nMaxLength+1];
pFX->m_prs->m_pvParamProxy[nField-1] = pvParam;
}
else
pvParam = pFX->m_prs->m_pvParamProxy[nField-1];
// Now fill in the data value
USES_CONVERSION;
lstrcpyA((char*)pvParam, T2A((LPCTSTR)value));
#endif // _UNICODE
*plLength = SQL_NTS;
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
pFX->m_nFieldType, SQL_C_CHAR, (SWORD)nColumnType,
nMaxLength, nScale, pvParam, 0, plLength));
value.ReleaseBuffer();
if (nRetCode != SQL_SUCCESS)
pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
// Add the member address to the param map
pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
}
return;
#ifdef _UNICODE
case CFieldExchange::RebindParam:
if (pFX->m_prs->m_nProxyParams != 0)
{
// Fill buffer (expected by SQLBindParameter) with new param data
USES_CONVERSION;
LPSTR lpszParam = (LPSTR)pFX->m_prs->m_pvParamProxy[nField-1];
lstrcpyA(lpszParam, T2A((LPCTSTR)value));
}
return;
#endif // _UNICODE
case CFieldExchange::BindFieldToColumn:
{
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
UINT cbColumn = pODBCInfo->m_nPrecision;
switch (pODBCInfo->m_nSQLType)
{
default:
#ifdef _DEBUG
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: CString converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
#endif // _DEBUG
break;
case SQL_LONGVARCHAR:
case SQL_CHAR:
case SQL_VARCHAR:
break;
case SQL_DECIMAL:
case SQL_NUMERIC:
// Add room for sign and decimal point
cbColumn += 2;
break;
case SQL_TIMESTAMP:
case SQL_DATE:
case SQL_TIME:
// May need extra space, i.e. "{TS mm/dd/yyyy hh:mm:ss}"
cbColumn += 10;
break;
case SQL_BIGINT:
// Add room for sign
cbColumn += 1;
break;
}
// Constrain to user specified max length
if (cbColumn > (UINT)nMaxLength)
cbColumn = nMaxLength;
// Set up binding addres
void* pvData;
value.GetBufferSetLength(cbColumn+1);
pvData = value.LockBuffer(); // will be overwritten if UNICODE
#ifdef _UNICODE
// Allocate proxy array if necessary
if (pFX->m_prs->m_pvFieldProxy == NULL)
{
pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
memset(pFX->m_prs->m_pvFieldProxy, 0,
pFX->m_prs->m_nFields*sizeof(void*));
pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
}
// Allocate non-unicode string for SQLBindCol (not necessary on Requery)
if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
pFX->m_prs->m_pvFieldProxy[nField-1] = new CHAR[cbColumn+2];
pvData = pFX->m_prs->m_pvFieldProxy[nField-1];
#endif // _UNICODE
AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
SQL_C_CHAR, pvData, cbColumn+1, plLength));
value.ReleaseBuffer();
if (!pFX->m_prs->Check(nRetCode))
pFX->m_prs->ThrowDBException(nRetCode);
// Add the member address to the field map
pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
}
return;
#ifdef _UNICODE
case CFieldExchange::BindFieldForUpdate:
if (pFX->m_prs->m_nProxyFields != 0)
{
// Fill buffer (expected by SQLSetPos) with new field data
USES_CONVERSION;
LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
lstrcpyA(lpszData, T2A((LPCTSTR)value));
pFX->Default(szName, (void *)lpszData, plLength, SQL_C_CHAR,
value.GetLength(), nMaxLength);
}
return;
#endif // _UNICODE
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value.GetBufferSetLength(0);
value.ReleaseBuffer();
}
else
{
#ifdef _UNICODE
// Copy value out of the proxy
value = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
#endif
LPTSTR lpsz = value.GetBuffer(0);
if (pFX->m_prs->m_pDatabase->m_bStripTrailingSpaces)
{
// find first trailing space
LPTSTR lpszFirstTrailing = NULL;
while (*lpsz != '\0')
{
if (*lpsz != ' ')
lpszFirstTrailing = NULL;
else
{
if (lpszFirstTrailing == NULL)
lpszFirstTrailing = lpsz;
}
lpsz = _tcsinc(lpsz);
}
// truncate
if (lpszFirstTrailing != NULL)
*lpszFirstTrailing = '\0';
}
value.ReleaseBuffer();
*plLength = value.GetLength();
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
// Set string 0 length
value.GetBufferSetLength(0);
value.ReleaseBuffer();
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = SQL_NTS;
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
#ifdef _UNICODE
case CFieldExchange::NameValue:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
*pFX->m_pstr += szName;
*pFX->m_pstr += '=';
}
// Fall through
case CFieldExchange::Value:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
// Get the field data
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pFX->m_prs->IsFieldStatusNull(nField - 1))
{
*plLength = SQL_NULL_DATA;
}
else
{
USES_CONVERSION;
lstrcpyA(lpszData, T2A((LPCTSTR)value));
*plLength = value.GetLength();
}
// If optimizing for bulk add, only need lengths & proxy set correctly
if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
{
*pFX->m_pstr += '?';
*pFX->m_pstr += pFX->m_lpszSeparator;
pFX->m_nParamFields++;
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
(UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
SQL_C_CHAR, pODBCInfo->m_nSQLType, nMaxLength, 0,
lpszData, 0, plLength));
// Add the member address to the param map
pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
}
}
return;
#endif // _UNICODE
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
if (!value.IsEmpty())
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value.IsEmpty())
pFX->m_prs->SetNullFieldStatus(nField - 1);
else
pFX->m_prs->ClearNullFieldStatus(nField - 1);
pFX->Default(szName, &value, plLength,
SQL_C_CHAR, value.GetLength(), nMaxLength);
return;
case CFieldExchange::LoadField:
{
// Get the field data
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
CString* pStrCachedValue = (CString*)pInfo->m_pvDataCache;
// Restore the status
pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus);
// If not NULL, restore the value and length
if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
{
value = *pStrCachedValue;
*plLength = value.GetLength();
#ifdef _UNICODE
// Must restore proxy for correct WHERE CURRENT OF operation
USES_CONVERSION;
LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
lstrcpyA(lpszData, T2A((LPCTSTR)value));
#endif // _UNICODE
}
else
{
*plLength = SQL_NULL_DATA;
}
#ifdef _DEBUG
// Buffer address must not change - ODBC's SQLBindCol depends upon this
void* pvBind;
#ifdef _UNICODE
pvBind = pFX->m_prs->m_pvFieldProxy[nField-1];
#else // !_UNICODE
pvBind = value.GetBuffer(0);
value.ReleaseBuffer();
#endif
if (pvBind != pInfo->m_pvBindAddress)
{
TRACE1("Error: CString buffer (column %u) address has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
}
return;
case CFieldExchange::StoreField:
AfxStoreField(*pFX->m_prs, nField, &value);
return;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
pInfo->m_pvDataCache = new CString;
pInfo->m_nDataType = AFX_RFX_TEXT;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = " << value;
return;
#endif // _DEBUG
}
}
void AFXAPI RFX_Int(CFieldExchange* pFX, LPCTSTR szName, int& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
if (pODBCInfo->m_nSQLType != SQL_C_SHORT)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: int converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
}
// fall through
default:
LDefault:
pFX->Default(szName, &value, plLength, SQL_C_LONG,
sizeof(value), 5);
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_INT_PSEUDO_NULL;
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_INT_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = sizeof(value);
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
if (value != AFX_RFX_INT_PSEUDO_NULL)
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value != AFX_RFX_INT_PSEUDO_NULL)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
goto LDefault;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// Data cached by value, no allocation necessary
pInfo->m_nDataType = AFX_RFX_INT;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = " << value;
return;
#endif // _DEBUG
}
}
void AFXAPI RFX_Long(CFieldExchange* pFX, LPCTSTR szName, long& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
if (pODBCInfo->m_nSQLType != SQL_C_LONG)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: long converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
}
// fall through
default:
LDefault:
pFX->Default(szName, &value, plLength, SQL_C_LONG,
sizeof(value), 10);
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_LONG_PSEUDO_NULL;
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_LONG_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = sizeof(value);
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
if (value != AFX_RFX_LONG_PSEUDO_NULL)
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value != AFX_RFX_LONG_PSEUDO_NULL)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
goto LDefault;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// Data cached by value, no allocation necessary
pInfo->m_nDataType = AFX_RFX_LONG;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = " << value;
return;
#endif // _DEBUG
}
}
void AFXAPI RFX_Byte(CFieldExchange* pFX, LPCTSTR szName, BYTE& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
if (pODBCInfo->m_nSQLType != SQL_TINYINT)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: BYTE converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
}
// fall through
default:
LDefault:
pFX->Default(szName, &value, plLength, SQL_TINYINT,
sizeof(value), 3);
break;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_BYTE_PSEUDO_NULL;
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_BYTE_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = sizeof(value);
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
if (value != AFX_RFX_BYTE_PSEUDO_NULL)
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value != AFX_RFX_BYTE_PSEUDO_NULL)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
goto LDefault;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// Data cached by value, no allocation necessary
pInfo->m_nDataType = AFX_RFX_BYTE;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = " << value;
return;
#endif // _DEBUG
}
}
void AFXAPI RFX_Bool(CFieldExchange* pFX, LPCTSTR szName, BOOL& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
if (pODBCInfo->m_nSQLType != SQL_BIT)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: BOOL converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
}
// Fall through
default:
LDefault:
pFX->Default(szName, &value, plLength, SQL_BIT,
sizeof(value), 1);
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_BOOL_PSEUDO_NULL;
}
else
// Cast BYTE into BOOL (int)
value = *(BYTE *)&value;
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_BOOL_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = sizeof(value);
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
if (value != AFX_RFX_BOOL_PSEUDO_NULL)
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value != AFX_RFX_BOOL_PSEUDO_NULL)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
goto LDefault;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// Data cached by value, no allocation necessary
pInfo->m_nDataType = AFX_RFX_BOOL;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = " << value;
return;
#endif // _DEBUG
}
}
// Note: CByteArray.m_pData must not be changed. This address is registered
// with ODBC and must remain valid until the recordset is released.
void AFXAPI RFX_Binary(CFieldExchange* pFX, LPCTSTR szName,
CByteArray& value, int nMaxLength)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
RETCODE nRetCode;
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
default:
LDefault:
pFX->Default(szName,
(value.GetSize() > 0) ? &value[0] : NULL, plLength,
SQL_C_BINARY, (int)value.GetSize(), (UINT)value.GetSize());
return;
case CFieldExchange::BindFieldToColumn:
{
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
UDWORD cbColumn = pODBCInfo->m_nPrecision;
#ifdef _DEBUG
if (pODBCInfo->m_nSQLType != SQL_BINARY &&
pODBCInfo->m_nSQLType != SQL_VARBINARY &&
pODBCInfo->m_nSQLType != SQL_LONGVARBINARY)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: CByteArray converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
// Constrain to user specified max length
if (cbColumn > (UINT)nMaxLength)
cbColumn = nMaxLength;
value.SetSize(cbColumn);
AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
SQL_C_BINARY, &value[0], (LONG)cbColumn, plLength));
if (!pFX->m_prs->Check(nRetCode))
pFX->m_prs->ThrowDBException(nRetCode);
// Add the member address to the field map
pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
}
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value.SetSize(1);
value[0] = AFX_RFX_BYTE_PSEUDO_NULL;
}
else
{
ASSERT(*plLength <= (LONG)nMaxLength);
((CDBByteArray&)value).SetLength((UINT)*plLength);
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value.SetSize(1);
value[0] = AFX_RFX_BYTE_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = value.GetSize();
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
if (value.GetSize() != 1 || value[0] != AFX_RFX_BYTE_PSEUDO_NULL)
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value.GetSize() != 1 || value[0] != AFX_RFX_BYTE_PSEUDO_NULL)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
goto LDefault;
case CFieldExchange::StoreField:
AfxStoreField(*pFX->m_prs, nField, &value);
return;
case CFieldExchange::LoadField:
AfxLoadField(*pFX->m_prs, nField, &value, plLength);
return;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
pInfo->m_pvDataCache = new CByteArray;
pInfo->m_nDataType = AFX_RFX_BINARY;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << ":";
value.Dump(*pFX->m_pdcDump);
return;
#endif // _DEBUG
}
}
void AFXAPI RFX_Date(CFieldExchange* pFX, LPCTSTR szName, CTime& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
RETCODE nRetCode;
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
default:
LDefault:
pFX->Default(szName, &value, plLength, SQL_C_TIMESTAMP,
sizeof(value), TIMESTAMP_PRECISION);
return;
case CFieldExchange::BindParam:
{
TIMESTAMP_STRUCT* pts;
pFX->m_prs->m_bRebindParams = TRUE;
if (pFX->m_prs->IsParamStatusNull(nField - 1))
{
pts = NULL;
*plLength = SQL_NULL_DATA;
}
else
{
// Allocate proxy array if necessary
if (pFX->m_prs->m_pvParamProxy == NULL)
{
pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
memset(pFX->m_prs->m_pvParamProxy, 0,
pFX->m_prs->m_nParams*sizeof(void*));
pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
}
// Allocate TIMESTAMP_STRUCT if necessary for SQLBindParameter
if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
{
pts = new TIMESTAMP_STRUCT;
pFX->m_prs->m_pvParamProxy[nField-1] = pts;
}
else
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
*plLength = sizeof(TIMESTAMP_STRUCT);
}
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
pFX->m_nFieldType, SQL_C_TIMESTAMP, SQL_C_TIMESTAMP,
TIMESTAMP_PRECISION, 0, pts, 0, plLength));
if (nRetCode != SQL_SUCCESS)
pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
// Add the member address to the param map
pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
}
return;
case CFieldExchange::RebindParam:
{
if (pFX->m_prs->m_nProxyParams != 0)
{
// Fill buffer (expected by SQLBindParameter) with new param data
TIMESTAMP_STRUCT* pts;
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
}
}
return;
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
if (pODBCInfo->m_nSQLType != SQL_DATE &&
pODBCInfo->m_nSQLType != SQL_TIME &&
pODBCInfo->m_nSQLType != SQL_TIMESTAMP)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: CTime converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
// Allocate proxy array if necessary
if (pFX->m_prs->m_pvFieldProxy == NULL)
{
pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
memset(pFX->m_prs->m_pvFieldProxy, 0,
pFX->m_prs->m_nFields*sizeof(void*));
pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
}
// Allocate TIMESTAMP_STRUCT for SQLBindCol (not necessary on Requery)
if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
pFX->m_prs->m_pvFieldProxy[nField-1] = new TIMESTAMP_STRUCT;
AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
SQL_C_TIMESTAMP, pFX->m_prs->m_pvFieldProxy[nField-1],
sizeof(TIMESTAMP_STRUCT), plLength));
if (!pFX->m_prs->Check(nRetCode))
pFX->m_prs->ThrowDBException(nRetCode);
// Add the member address to the field map
pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
}
return;
case CFieldExchange::BindFieldForUpdate:
if (pFX->m_prs->m_nProxyFields != 0)
{
// Fill buffer (expected by SQLSetPos) with new field data
TIMESTAMP_STRUCT* pts;
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvFieldProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
pFX->Default(szName, (void *)pts, plLength, SQL_C_TIMESTAMP,
sizeof(TIMESTAMP_STRUCT), TIMESTAMP_PRECISION);
}
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_DATE_PSEUDO_NULL;
}
else
{
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pts->year < 1970 || pts->year > 2038)
{
// Time value out of range, return NULL
#ifdef _DEBUG
if (afxTraceFlags & traceDatabase)
TRACE0("Warning: date value out of range, returning NULL value.\n");
#endif
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_DATE_PSEUDO_NULL;
}
else
{
#ifdef _DEBUG
if ((afxTraceFlags & traceDatabase) && pts->fraction != 0)
TRACE0("Warning: ignoring milliseconds.\n");
#endif
value = CTime(pts->year, pts->month, pts->day,
pts->hour, pts->minute, pts->second);
}
}
return;
case CFieldExchange::NameValue:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
*pFX->m_pstr += szName;
*pFX->m_pstr += '=';
}
// Fall through
case CFieldExchange::Value:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pFX->m_prs->IsFieldStatusNull(nField - 1))
{
*plLength = SQL_NULL_DATA;
}
else
{
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
*plLength = sizeof(TIMESTAMP_STRUCT);
}
// If optimizing for bulk add, only need lengths & proxy set correctly
if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
{
*pFX->m_pstr += '?';
*pFX->m_pstr += pFX->m_lpszSeparator;
pFX->m_nParamFields++;
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
(UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
SQL_C_TIMESTAMP, pODBCInfo->m_nSQLType,
TIMESTAMP_PRECISION, 0, pts, 0, plLength));
// Add the member address to the param map
pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
}
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = AFX_RFX_DATE_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = sizeof(TIMESTAMP_STRUCT);
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
CTime timeNull = AFX_RFX_DATE_PSEUDO_NULL;
if (value != timeNull)
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
{
CTime timeNull = AFX_RFX_DATE_PSEUDO_NULL;
if (value != timeNull)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
goto LDefault;
case CFieldExchange::LoadField:
{
// Get the field data
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// Restore the status
pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus);
// If not NULL, restore the value, length and proxy
if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
{
AfxCopyValueByRef(pInfo->m_pvDataCache, &value,
plLength, pInfo->m_nDataType);
// Restore proxy for correct WHERE CURRENT OF operations
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
}
else
*plLength = SQL_NULL_DATA;
#ifdef _DEBUG
// Buffer address must not change - ODBC's SQLBindCol depends upon this
if (pInfo->m_pvBindAddress != pFX->m_prs->m_pvFieldProxy[nField-1])
{
TRACE1("Error: CString buffer (column %u) address has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
}
return;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
pInfo->m_pvDataCache = new CTime;
pInfo->m_nDataType = AFX_RFX_DATE;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = " << value;
return;
#endif // _DEBUG
}
}
void AFXAPI RFX_Date(CFieldExchange* pFX, LPCTSTR szName,
TIMESTAMP_STRUCT& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
if (pODBCInfo->m_nSQLType != SQL_DATE &&
pODBCInfo->m_nSQLType != SQL_TIME &&
pODBCInfo->m_nSQLType != SQL_TIMESTAMP)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: TIMESTAMP_STRUCT converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
// fall through
}
default:
LDefault:
pFX->Default(szName, &value, plLength, SQL_C_TIMESTAMP,
sizeof(value), TIMESTAMP_PRECISION);
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value.year = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.month = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.day = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.hour = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.minute = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.second = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.fraction = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value.year = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.month = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.day = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.hour = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.minute = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.second = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
value.fraction = AFX_RFX_TIMESTAMP_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = sizeof(TIMESTAMP_STRUCT);
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
if (!(value.year == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.month == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.day == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.hour == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.minute == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.second == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.fraction == AFX_RFX_TIMESTAMP_PSEUDO_NULL ))
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (!(value.year == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.month == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.day == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.hour == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.minute == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.second == AFX_RFX_TIMESTAMP_PSEUDO_NULL &&
value.fraction == AFX_RFX_TIMESTAMP_PSEUDO_NULL ))
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
goto LDefault;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
pInfo->m_pvDataCache = new TIMESTAMP_STRUCT;
pInfo->m_nDataType = AFX_RFX_TIMESTAMP;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << ".year = " << (int)value.year;
*pFX->m_pdcDump << "\n" << szName << ".month = " << value.month;
*pFX->m_pdcDump << "\n" << szName << ".day = " << value.day;
*pFX->m_pdcDump << "\n" << szName << ".hour = " << value.hour;
*pFX->m_pdcDump << "\n" << szName << ".minute = " << value.minute;
*pFX->m_pdcDump << "\n" << szName << ".second = " << value.second;
*pFX->m_pdcDump << "\n" << szName << ".fraction = " << value.fraction;
return;
#endif // _DEBUG
}
}
void AFXAPI RFX_LongBinary(CFieldExchange* pFX, LPCTSTR szName,
CLongBinary& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
RETCODE nRetCode;
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
case CFieldExchange::Name:
pFX->m_prs->m_bLongBinaryColumns = TRUE;
pFX->Default(szName, &value, plLength, SQL_C_DEFAULT, 0, 0);
return;
case CFieldExchange::BindFieldToColumn:
// Don't bind if using update SQL, simply do SQLGetData on Fixup
if (!pFX->m_prs->m_bUseUpdateSQL && pFX->m_prs->CanUpdate())
{
// Bind for updates with cb=0 now. Driver may not support post Execute or ExtendedFetch binding
AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField, SQL_C_DEFAULT,
&value, 0, plLength));
if (!pFX->m_prs->Check(nRetCode))
pFX->m_prs->ThrowDBException(nRetCode);
}
// Add the member address to the field map
pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
return;
#ifdef _DEBUG
case CFieldExchange::BindParam:
// CLongBinary parameters are not supported
ASSERT(FALSE);
case CFieldExchange::MarkForAddNew:
case CFieldExchange::MarkForUpdate:
// We do not archive LongBinary values
case CFieldExchange::StoreField:
case CFieldExchange::LoadField:
// We do not archive LongBinary values
#endif // _DEBUG
default:
return;
case CFieldExchange::Fixup:
// Get the size of the long binary field
*plLength = pFX->GetLongBinarySize(nField);
// Get the data if necessary
if (*plLength != SQL_NULL_DATA)
pFX->GetLongBinaryData(nField, value, plLength);
// Set the status and length
if (*plLength == SQL_NULL_DATA)
{
// Field NULL, set length and status
value.m_dwDataLength = 0;
pFX->m_prs->SetNullFieldStatus(nField - 1);
}
else
{
// Field not NULL, clear the status (length already set)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
return;
case CFieldExchange::NameValue:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
*pFX->m_pstr += szName;
*pFX->m_pstr += '=';
}
// Fall through
case CFieldExchange::Value:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
// If user marked column NULL, reflect this in length
if (pFX->m_prs->IsFieldStatusNull(nField - 1))
*plLength = SQL_NULL_DATA;
else
{
// Indicate data will be sent after SQLExecute
*plLength = SQL_DATA_AT_EXEC;
}
// If optimizing for bulk add, only need lengths set correctly
if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
{
*pFX->m_pstr += '?';
*pFX->m_pstr += pFX->m_lpszSeparator;
pFX->m_nParamFields++;
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
(UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
SQL_C_DEFAULT, pODBCInfo->m_nSQLType,
value.m_dwDataLength, 0, &value, 0, plLength));
if (nRetCode != SQL_SUCCESS)
pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
}
}
return;
case CFieldExchange::BindFieldForUpdate:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
// If user marked column NULL, reflect this in length
if (pFX->m_prs->IsFieldStatusNull(nField - 1))
*plLength = SQL_NULL_DATA;
else
{
// Length is signed value, it's limited by LONG_MAX
if (value.m_dwDataLength >
(ULONG)(LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET)))
{
ASSERT(FALSE);
*plLength = LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET);
}
else
*plLength = value.m_dwDataLength;
*plLength = SQL_LEN_DATA_AT_EXEC(*plLength);
}
}
else
*plLength = SQL_IGNORE;
return;
case CFieldExchange::UnbindFieldForUpdate:
*plLength = value.m_dwDataLength;
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value.m_dwDataLength = 0;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
if (pFX->m_prs->m_bUseUpdateSQL)
*plLength = SQL_DATA_AT_EXEC;
else
{
// Length is signed value, it's limited by LONG_MAX
if (value.m_dwDataLength >
(ULONG)(LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET)))
{
ASSERT(FALSE);
*plLength = LONG_MAX - labs(SQL_LEN_DATA_AT_EXEC_OFFSET);
}
else
*plLength = value.m_dwDataLength;
*plLength = SQL_LEN_DATA_AT_EXEC(*plLength);
}
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::AllocCache:
// Caching not supported for long binary
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = ";
value.Dump(*pFX->m_pdcDump);
return;
#endif // _DEBUG
}
}
long CFieldExchange::GetLongBinarySize(int nField)
{
RETCODE nRetCode;
int nDummy;
long lSize;
// Give empty buffer to find size of entire LongBinary
AFX_ODBC_CALL(::SQLGetData(m_prs->m_hstmt,
(UWORD)nField, SQL_C_DEFAULT, &nDummy, 0, &lSize));
switch (nRetCode)
{
case SQL_SUCCESS:
break;
case SQL_SUCCESS_WITH_INFO:
#ifdef _DEBUG
if (afxTraceFlags & traceDatabase)
{
CDBException* e = new CDBException(nRetCode);
e->BuildErrorString(m_prs->m_pDatabase,
m_prs->m_hstmt, FALSE);
// Ignore data truncated messages
if (e->m_strStateNativeOrigin.Find(_T("State:01004")) < 0)
{
TRACE0("Warning: ODBC Success With Info, ");
e->TraceErrorMessage(e->m_strError);
e->TraceErrorMessage(e->m_strStateNativeOrigin);
}
e->Delete();
}
#endif // _DEBUG
break;
default:
m_prs->ThrowDBException(nRetCode);
}
return lSize;
}
void CFieldExchange::GetLongBinaryData(int nField, CLongBinary& lb,
long* plSize)
{
RETCODE nRetCode;
long lActualDataSize = 0;
long lChunkDataSize;
long lReallocSize;
const BYTE* lpLongBinary;
lb.m_dwDataLength = 0;
// Determine initial chunk sizes
if (*plSize == SQL_NO_TOTAL)
{
lChunkDataSize = m_lDefaultLBFetchSize;
lReallocSize = m_lDefaultLBReallocSize;
}
else
{
lChunkDataSize = *plSize;
lReallocSize = *plSize;
}
do
{
// Check if CLongBianary is big enough
lpLongBinary = ReallocLongBinary(lb,
(long)lb.m_dwDataLength + lChunkDataSize,
(long)lb.m_dwDataLength + lReallocSize);
// Adjust the pointer so that data added at end
lpLongBinary += lb.m_dwDataLength;
AFX_ODBC_CALL(::SQLGetData(m_prs->m_hstmt, (UWORD)nField,
SQL_C_BINARY, (UCHAR*)lpLongBinary, lChunkDataSize, &lActualDataSize));
::GlobalUnlock(lb.m_hData);
switch (nRetCode)
{
case SQL_NO_DATA_FOUND:
m_prs->SetNullFieldStatus(nField - 1);
*plSize = SQL_NULL_DATA;
break;
case SQL_SUCCESS:
// All data fetched
lb.m_dwDataLength += lActualDataSize;
*plSize = (long)lb.m_dwDataLength;
return;
case SQL_SUCCESS_WITH_INFO:
{
CDBException* e = new CDBException(nRetCode);
e->BuildErrorString(m_prs->m_pDatabase, m_prs->m_hstmt,
FALSE);
// Ignore data truncated messages
if (e->m_strStateNativeOrigin.Find(_T("State:01004")) < 0)
{
#ifdef _DEBUG
if (afxTraceFlags & traceDatabase)
{
TRACE0("Warning: ODBC Success With Info, ");
e->TraceErrorMessage(e->m_strError);
e->TraceErrorMessage(e->m_strStateNativeOrigin);
}
#endif // _DEBUG
// Must be some other warning, should be finished
lb.m_dwDataLength += lActualDataSize;
}
else
{
// Should only happen if SQL_NO_TOTAL
// Increment the length by the chunk size for subsequent SQLGetData call
lb.m_dwDataLength += lChunkDataSize;
// Recalculate chunk and alloc sizes
lChunkDataSize = m_prs->GetLBFetchSize(lChunkDataSize);
lReallocSize = m_prs->GetLBReallocSize(lReallocSize);
}
*plSize = (long)lb.m_dwDataLength;
e->Delete();
}
break;
default:
m_prs->ThrowDBException(nRetCode);
}
} while (lActualDataSize == SQL_NO_TOTAL);
}
BYTE* CFieldExchange::ReallocLongBinary(CLongBinary& lb, long lSizeRequired,
long lReallocSize)
{
// realloc max of lSizeRequired, lReallocSize (m_dwDataLength untouched)
if (lSizeRequired < 0)
{
ASSERT(FALSE);
lSizeRequired = 0;
}
HGLOBAL hOldData = NULL;
// Allocate or Realloc as req'd
if (lb.m_hData == NULL)
lb.m_hData = ::GlobalAlloc(GMEM_MOVEABLE, lReallocSize);
else
{
DWORD dwSize = ::GlobalSize(lb.m_hData);
if (dwSize < (DWORD)lSizeRequired)
{
// Save the old handle in case ReAlloc fails
hOldData = lb.m_hData;
// Allocate more memory if necessary
lb.m_hData = ::GlobalReAlloc(lb.m_hData,
__max(lSizeRequired, lReallocSize), GMEM_MOVEABLE);
}
}
// Validate the memory was allocated and can be locked
if (lb.m_hData == NULL)
{
// Restore the old handle (not NULL if Realloc failed)
lb.m_hData = hOldData;
AfxThrowMemoryException();
}
BYTE* lpLongBinary = (BYTE*)::GlobalLock(lb.m_hData);
if (lpLongBinary == NULL)
{
::GlobalFree(lb.m_hData);
lb.m_hData = NULL;
AfxThrowMemoryException();
}
return lpLongBinary;
}
//////////////////////////////////////////////////////////////////////////////
// Recordset Field Exchange Helpers
void AFXAPI AfxStoreField(CRecordset& rs, UINT nField, void* pvField)
{
// Get the field data
CFieldInfo* pInfo = &rs.m_rgFieldInfos[nField - 1];
// Cache the status
pInfo->m_bStatus = rs.GetFieldStatus(nField - 1);
// Save the data
if (!rs.IsFieldStatusNull(nField - 1))
{
// Don't need to save length for variable len
// objects as CString and CByteArray track len internally
long nDummyLength;
if (pInfo->m_nDataType == AFX_RFX_BOOL ||
pInfo->m_nDataType == AFX_RFX_BYTE ||
pInfo->m_nDataType == AFX_RFX_INT ||
pInfo->m_nDataType == AFX_RFX_LONG ||
pInfo->m_nDataType == AFX_RFX_SINGLE)
{
// If caching data by value, pass a ref
AfxCopyValueByRef(pvField, &pInfo->m_pvDataCache,
&nDummyLength, pInfo->m_nDataType);
}
else
{
AfxCopyValueByRef(pvField, pInfo->m_pvDataCache,
&nDummyLength, pInfo->m_nDataType);
}
}
#ifdef _DEBUG
// Cache the bind address expected by ODBC
switch(pInfo->m_nDataType)
{
default:
// All types that are bound directly
pInfo->m_pvBindAddress = pvField;
break;
case AFX_RFX_TEXT:
#ifdef _UNICODE
pInfo->m_pvBindAddress = rs.m_pvFieldProxy[nField-1];
#else
pInfo->m_pvBindAddress = ((CString*)pvField)->GetBuffer(0);
((CString*)pvField)->ReleaseBuffer();
#endif
break;
case AFX_RFX_DATE:
pInfo->m_pvBindAddress = rs.m_pvFieldProxy[nField-1];
break;
case AFX_RFX_BINARY:
pInfo->m_pvBindAddress = ((CByteArray*)pvField)->GetData();
break;
}
#endif
}
void AFXAPI AfxLoadField(CRecordset& rs, UINT nField,
void* pvField, long* plLength)
{
// Get the field data
CFieldInfo* pInfo = &rs.m_rgFieldInfos[nField - 1];
// Assumes old field status cleared out
rs.SetFieldStatus(nField - 1, pInfo->m_bStatus);
// If not NULL, restore the value and the length
if (!rs.IsFieldStatusNull(nField - 1))
{
if (pInfo->m_nDataType == AFX_RFX_BOOL ||
pInfo->m_nDataType == AFX_RFX_BYTE ||
pInfo->m_nDataType == AFX_RFX_INT ||
pInfo->m_nDataType == AFX_RFX_LONG ||
pInfo->m_nDataType == AFX_RFX_SINGLE)
{
// If caching data by value, pass a ref
AfxCopyValueByRef(&pInfo->m_pvDataCache, pvField,
plLength, pInfo->m_nDataType);
}
else
{
AfxCopyValueByRef(pInfo->m_pvDataCache, pvField,
plLength, pInfo->m_nDataType);
}
}
else
*plLength = SQL_NULL_DATA;
#ifdef _DEBUG
// Buffer address must not change - ODBC's SQLBindCol depends upon this
if (pInfo->m_nDataType == AFX_RFX_BINARY)
{
// Change pvField to point to the data of the CByteArray
pvField = ((CByteArray*)pvField)->GetData();
}
if (pInfo->m_pvBindAddress != pvField)
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
}
BOOL AFXAPI AfxCompareValueByRef(void* pvSrc, void* pvDest, int nSrcType)
{
ASSERT(pvSrc != NULL);
ASSERT(pvDest != NULL);
BOOL bCompare = FALSE;
switch(nSrcType)
{
case AFX_RFX_LONGBINARY:
// Caching long binary Src not supported
default:
ASSERT(FALSE);
break;
case AFX_RFX_TEXT:
if (*(CString*)pvDest == *(CString*)pvSrc)
bCompare = TRUE;
break;
case AFX_RFX_BINARY:
{
CByteArray* pByteArraySrc = (CByteArray*)pvSrc;
CByteArray* pByteArrayDest = (CByteArray*)pvDest;
// If sizes compare, compare the Src
int nSize = pByteArraySrc->GetSize();
if (nSize == pByteArrayDest->GetSize())
{
if (memcmp(&pByteArrayDest[0], &pByteArraySrc[0], nSize) == 0)
bCompare = TRUE;
}
}
break;
case AFX_RFX_BOOL:
if (*(BOOL*)pvDest == *(BOOL*)pvSrc)
bCompare = TRUE;
break;
case AFX_RFX_BYTE:
if (*(BYTE*)pvDest == *(BYTE*)pvSrc)
bCompare = TRUE;
break;
case AFX_RFX_INT:
if (*(int*)pvDest == *(int*)pvSrc)
bCompare = TRUE;
break;
case AFX_RFX_LONG:
if (*(long*)pvDest == *(long*)pvSrc)
bCompare = TRUE;
break;
case AFX_RFX_SINGLE:
if (*(float*)pvDest == *(float*)pvSrc)
bCompare = TRUE;
break;
case AFX_RFX_DOUBLE:
if (*(double*)pvDest == *(double*)pvSrc)
bCompare = TRUE;
break;
case AFX_RFX_DATE:
if (*(CTime*)pvDest == *(CTime*)pvSrc)
bCompare = TRUE;
break;
case AFX_RFX_TIMESTAMP:
{
TIMESTAMP_STRUCT* pSrc = (TIMESTAMP_STRUCT*)pvSrc;
TIMESTAMP_STRUCT* pDest = (TIMESTAMP_STRUCT*)pvDest;
if ((pSrc->year == pDest->year &&
pSrc->month == pDest->month &&
pSrc->day == pDest->day &&
pSrc->hour == pDest->hour &&
pSrc->minute == pDest->minute &&
pSrc->second == pDest->second &&
pSrc->fraction == pDest->fraction))
{
bCompare = TRUE;
}
}
break;
}
return bCompare;
}
void AFXAPI AfxCopyValueByRef(void* pvSrc, void* pvDest, long* plLength, int nDestType)
{
ASSERT(pvSrc != NULL);
ASSERT(pvDest != NULL);
ASSERT(plLength != NULL);
switch (nDestType)
{
case AFX_RFX_LONGBINARY:
// Caching long binary Dest not supported
default:
ASSERT(FALSE);
break;
case AFX_RFX_TEXT:
*(CString*)pvDest = *(CString*)pvSrc;
*plLength = ((CString*)pvSrc)->GetLength();
break;
case AFX_RFX_BINARY:
((CByteArray*)pvDest)->Copy(*(CByteArray*)pvSrc);
*plLength = ((CByteArray*)pvSrc)->GetSize();
break;
case AFX_RFX_BOOL:
*(BOOL*)pvDest = *(BOOL*)pvSrc;
*plLength = sizeof(BOOL);
break;
case AFX_RFX_BYTE:
*(BYTE*)pvDest = *(BYTE*)pvSrc;
*plLength = sizeof(BYTE);
break;
case AFX_RFX_INT:
*(int*)pvDest = *(int*)pvSrc;
*plLength = sizeof(int);
break;
case AFX_RFX_LONG:
*(long*)pvDest = *(long*)pvSrc;
*plLength = sizeof(long);
break;
case AFX_RFX_SINGLE:
*(float*)pvDest = *(float*)pvSrc;
*plLength = sizeof(float);
break;
case AFX_RFX_DOUBLE:
*(double*)pvDest = *(double*)pvSrc;
*plLength = sizeof(double);
break;
case AFX_RFX_DATE:
*(CTime*)pvDest = *(CTime*)pvSrc;
*plLength = sizeof(TIMESTAMP_STRUCT);
break;
case AFX_RFX_TIMESTAMP:
{
TIMESTAMP_STRUCT* pDest = (TIMESTAMP_STRUCT*)pvDest;
TIMESTAMP_STRUCT* pSrc = (TIMESTAMP_STRUCT*)pvSrc;
pDest->year = pSrc->year;
pDest->month = pSrc->month;
pDest->day = pSrc->day;
pDest->hour = pSrc->hour;
pDest->minute = pSrc->minute;
pDest->second = pSrc->second;
pDest->fraction = pSrc->fraction;
*plLength = sizeof(TIMESTAMP_STRUCT);
}
break;
}
}
//////////////////////////////////////////////////////////////////////////////
// Bulk Recordset Field Exchange
void AFXAPI RFX_Text_Bulk(CFieldExchange* pFX, LPCTSTR szName,
LPSTR* prgStrVals, long** prgLengths, int nMaxLength)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
switch (pFX->m_nOperation)
{
case CFieldExchange::AllocMultiRowBuffer:
{
// The buffer pointer better be initialized to NULL
// or cleanup in exceptional cases mail fail
ASSERT(*prgStrVals == NULL);
ASSERT(*prgLengths == NULL);
int nRowsetSize = pFX->m_prs->GetRowsetSize();
// Allocate buffers to hold data and length
*prgStrVals = new char[nRowsetSize * nMaxLength];
*prgLengths = new long[nRowsetSize];
}
break;
case CFieldExchange::DeleteMultiRowBuffer:
delete [] *prgStrVals;
*prgStrVals = NULL;
delete [] *prgLengths;
*prgLengths = NULL;
break;
default:
AfxRFXBulkDefault(pFX, szName, *prgStrVals, *prgLengths,
SQL_C_CHAR, nMaxLength);
break;
}
}
void AFXAPI RFX_Bool_Bulk(CFieldExchange* pFX, LPCTSTR szName,
BOOL** prgBoolVals, long** prgLengths)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
switch (pFX->m_nOperation)
{
case CFieldExchange::AllocMultiRowBuffer:
{
// The buffer pointer better be initialized to NULL
// or cleanup in exceptional cases mail fail
ASSERT(*prgBoolVals == NULL);
ASSERT(*prgLengths == NULL);
int nRowsetSize = pFX->m_prs->GetRowsetSize();
// Allocate buffers to hold data and length
*prgBoolVals = new BOOL[nRowsetSize];
*prgLengths = new long[nRowsetSize];
}
break;
case CFieldExchange::DeleteMultiRowBuffer:
delete [] *prgBoolVals;
*prgBoolVals = NULL;
delete [] *prgLengths;
*prgLengths = NULL;
break;
default:
AfxRFXBulkDefault(pFX, szName, *prgBoolVals, *prgLengths,
SQL_C_LONG, sizeof(BOOL));
break;
}
}
void AFXAPI RFX_Int_Bulk(CFieldExchange* pFX, LPCTSTR szName,
int** prgIntVals, long** prgLengths)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
switch (pFX->m_nOperation)
{
case CFieldExchange::AllocMultiRowBuffer:
{
// The buffer pointer better be initialized to NULL
// or cleanup in exceptional cases mail fail
ASSERT(*prgIntVals == NULL);
ASSERT(*prgLengths == NULL);
int nRowsetSize = pFX->m_prs->GetRowsetSize();
// Allocate buffers to hold data and length
*prgIntVals = new int[nRowsetSize];
*prgLengths = new long[nRowsetSize];
}
break;
case CFieldExchange::DeleteMultiRowBuffer:
delete [] *prgIntVals;
*prgIntVals = NULL;
delete [] *prgLengths;
*prgLengths = NULL;
break;
default:
AfxRFXBulkDefault(pFX, szName, *prgIntVals, *prgLengths,
SQL_C_LONG, sizeof(int));
break;
}
}
void AFXAPI RFX_Long_Bulk(CFieldExchange* pFX, LPCTSTR szName,
long** prgLongVals, long** prgLengths)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
switch (pFX->m_nOperation)
{
case CFieldExchange::AllocMultiRowBuffer:
{
// The buffer pointer better be initialized to NULL
// or cleanup in exceptional cases mail fail
ASSERT(*prgLongVals == NULL);
ASSERT(*prgLengths == NULL);
int nRowsetSize = pFX->m_prs->GetRowsetSize();
// Allocate buffers to hold data and length
*prgLongVals = new long[nRowsetSize];
*prgLengths = new long[nRowsetSize];
}
break;
case CFieldExchange::DeleteMultiRowBuffer:
delete [] *prgLongVals;
*prgLongVals = NULL;
delete [] *prgLengths;
*prgLengths = NULL;
break;
default:
AfxRFXBulkDefault(pFX, szName, *prgLongVals, *prgLengths,
SQL_C_LONG, sizeof(long));
break;
}
}
void AFXAPI RFX_Date_Bulk(CFieldExchange* pFX, LPCTSTR szName,
TIMESTAMP_STRUCT** prgTSVals, long** prgLengths)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
switch (pFX->m_nOperation)
{
case CFieldExchange::AllocMultiRowBuffer:
{
// The buffer pointer better be initialized to NULL
// or cleanup in exceptional cases mail fail
ASSERT(*prgTSVals == NULL);
ASSERT(*prgLengths == NULL);
int nRowsetSize = pFX->m_prs->GetRowsetSize();
// Allocate buffers to hold data and length
*prgTSVals = new TIMESTAMP_STRUCT[nRowsetSize];
*prgLengths = new long[nRowsetSize];
}
break;
case CFieldExchange::DeleteMultiRowBuffer:
delete [] *prgTSVals;
*prgTSVals = NULL;
delete [] *prgLengths;
*prgLengths = NULL;
break;
default:
AfxRFXBulkDefault(pFX, szName, *prgTSVals, *prgLengths,
SQL_C_TIMESTAMP, sizeof(TIMESTAMP_STRUCT));
break;
}
}
void AFXAPI RFX_Byte_Bulk(CFieldExchange* pFX, LPCTSTR szName,
BYTE** prgByteVals, long** prgLengths)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
switch (pFX->m_nOperation)
{
case CFieldExchange::AllocMultiRowBuffer:
{
// The buffer pointer better be initialized to NULL
// or cleanup in exceptional cases mail fail
ASSERT(*prgByteVals == NULL);
ASSERT(*prgLengths == NULL);
int nRowsetSize = pFX->m_prs->GetRowsetSize();
// Allocate buffers to hold data and length
*prgByteVals = new BYTE[nRowsetSize];
*prgLengths = new long[nRowsetSize];
}
break;
case CFieldExchange::DeleteMultiRowBuffer:
delete [] *prgByteVals;
*prgByteVals = NULL;
delete [] *prgLengths;
*prgLengths = NULL;
break;
default:
AfxRFXBulkDefault(pFX, szName, *prgByteVals, *prgLengths,
SQL_C_TINYINT, sizeof(BYTE));
break;
}
}
void AFXAPI RFX_Binary_Bulk(CFieldExchange* pFX, LPCTSTR szName,
BYTE** prgByteVals, long** prgLengths, int nMaxLength)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
switch (pFX->m_nOperation)
{
case CFieldExchange::AllocMultiRowBuffer:
{
// The buffer pointer better be initialized to NULL
// or cleanup in exceptional cases mail fail
ASSERT(*prgByteVals == NULL);
ASSERT(*prgLengths == NULL);
int nRowsetSize = pFX->m_prs->GetRowsetSize();
// Allocate buffers to hold data and length
*prgByteVals = new BYTE[nRowsetSize * nMaxLength];
*prgLengths = new long[nRowsetSize];
}
break;
case CFieldExchange::DeleteMultiRowBuffer:
delete [] *prgByteVals;
*prgByteVals = NULL;
delete [] *prgLengths;
*prgLengths = NULL;
break;
default:
AfxRFXBulkDefault(pFX, szName, *prgByteVals, *prgLengths,
SQL_C_BINARY, nMaxLength);
break;
}
}
void AFXAPI AfxRFXBulkDefault(CFieldExchange* pFX, LPCTSTR szName,
void* pv, long* rgLengths, int nCType, UINT cbValue)
{
RETCODE nRetCode;
switch(pFX->m_nOperation)
{
default:
// Operation not valid for bulk fetch
ASSERT(FALSE);
return;
case CFieldExchange::Name:
// We require a name
ASSERT(lstrlen(szName) != 0);
*pFX->m_pstr += szName;
*pFX->m_pstr += pFX->m_lpszSeparator;
break;
case CFieldExchange::BindFieldToColumn:
AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt,
(UWORD)pFX->m_nFields, nCType, pv, cbValue, rgLengths));
if (!pFX->m_prs->Check(nRetCode))
pFX->m_prs->ThrowDBException(nRetCode);
break;
}
}
//////////////////////////////////////////////////////////////////////////////
// Inline function declarations expanded out-of-line
#ifndef _AFX_ENABLE_INLINES
static char _szAfxDbInl[] = "afxdb.inl";
#undef THIS_FILE
#define THIS_FILE _szAfxDbInl
#define _AFXDBRFX_INLINE
#include "afxdb.inl"
#endif
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
/////////////////////////////////////////////////////////////////////////////