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.
 
 
 
 
 
 

2454 lines
61 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_bFieldFound = FALSE;
m_pstr = NULL;
m_hstmt = SQL_NULL_HSTMT;
m_par = NULL;
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 == param);
*pnField = ++m_nParams;
// Recordset's m_nParams must match number of Params!
ASSERT(m_nParams <= m_prs->m_nParams);
}
switch (m_nOperation)
{
// these can work on either field type
case SetFieldNull:
case IsFieldNull:
case IsFieldNullable:
return TRUE;
// only valid on a param field type
case BindParam:
case RebindParam:
return m_nFieldType != outputColumn;
// valid only on an outputColumn field type
default:
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->IsFieldFlagNull(nField, param))
*plLength = SQL_NULL_DATA;
else
*plLength = cbValue;
// For params, CType is same as SQL type
AFX_SQL_SYNC(::SQLBindParameter(m_hstmt, (UWORD)nField,
SQL_PARAM_INPUT, (SWORD)nCType, (SWORD)nCType, cbPrecision, 0,
pv, 0, plLength));
if (nRetCode != SQL_SUCCESS)
m_prs->ThrowDBException(nRetCode, m_hstmt);
return;
case RebindParam:
// Only need for date/time parameters and UNICODE text
return;
case BindFieldForUpdate:
if (!m_prs->IsFieldFlagDirty(nField, m_nFieldType))
{
// If not dirty, set length to SQL_IGNORE for SQLSetPos updates
*plLength = SQL_IGNORE;
}
else if (!m_prs->IsFieldFlagNull(nField, m_nFieldType))
{
// 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->IsFieldFlagDirty(nField, m_nFieldType))
*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);
return;
case Name:
if (m_prs->IsFieldFlagDirty(nField, m_nFieldType))
{
// We require a name
ASSERT(lstrlen(szName) != 0);
*m_pstr += szName;
*m_pstr += m_lpszSeparator;
}
return;
case NameValue:
if (m_prs->IsFieldFlagDirty(nField, m_nFieldType))
{
*m_pstr += szName;
*m_pstr += '=';
}
// Fall through
case Value:
if (m_prs->IsFieldFlagDirty(nField, m_nFieldType))
{
// If user marked column NULL, reflect this in length
if (m_prs->IsFieldFlagNull(nField, m_nFieldType))
*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++;
AFX_SQL_SYNC(::SQLBindParameter(m_hstmt,
(UWORD)m_nParamFields, SQL_PARAM_INPUT,
(SWORD)nCType, (SWORD)GetColumnType(nField),
cbPrecision, 0, pv, 0, plLength));
if (nRetCode != SQL_SUCCESS)
m_prs->ThrowDBException(nRetCode, m_hstmt);
}
}
return;
case SetFieldDirty:
if ((m_pvField == NULL && m_nFieldType == outputColumn)
|| m_pvField == pv)
{
if (m_bField)
m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, m_nFieldType);
else
m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, m_nFieldType);
#ifdef _DEBUG
m_bFieldFound = TRUE;
#endif
}
return;
case IsFieldDirty:
if ((m_pvField == NULL && m_nFieldType == outputColumn)
|| m_pvField == pv)
{
if (m_prs->IsFieldFlagDirty(nField, m_nFieldType))
m_bField = TRUE;
#ifdef _DEBUG
m_bFieldFound = TRUE;
#endif
}
return;
case IsFieldNull:
if ((m_pvField == NULL && m_nFieldType == outputColumn)
|| m_pvField == pv)
{
if (m_prs->IsFieldFlagNull(nField, m_nFieldType))
m_bField = TRUE;
#ifdef _DEBUG
m_bFieldFound = TRUE;
#endif
}
return;
case IsFieldNullable:
if ((m_pvField == NULL && m_nFieldType == outputColumn)
|| m_pvField == pv)
{
UINT cbColumn;
int nScale;
int nNullable;
if (m_nFieldType == param)
{
// Param can be set NULL, but WHERE clause not parsed to check validity
m_bField = TRUE;
}
else
{
ASSERT(m_nFieldType == outputColumn);
GetColumnType(nField, &cbColumn, &nScale, &nNullable);
if (nNullable == SQL_NULLABLE ||
nNullable == SQL_NULLABLE_UNKNOWN)
m_bField = TRUE;
}
#ifdef _DEBUG
m_bFieldFound = TRUE;
#endif
}
return;
case MarkForUpdate:
{
// If user changed field value from previous value, mark field dirty
BYTE bFlags;
*m_par >> bFlags;
if ((bFlags & AFX_SQL_FIELD_FLAG_NULL))
{
if (!m_prs->IsFieldFlagNull(nField,
m_nFieldType))
{
m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, m_nFieldType);
}
}
else
{
// TRUE if NULL status differs
BOOL bDirty = m_prs->IsFieldFlagNull(nField,
m_nFieldType);
UINT nLength;
m_par->Read(&nLength, sizeof(nLength));
// Lengths differ
if (nLength != cbValue)
bDirty = TRUE;
// Compare values
BYTE *pbValue = (BYTE *)pv;
while (nLength--)
{
BYTE bSaved;
*m_par >> bSaved;
// Values differ
if (!bDirty && *pbValue++ != bSaved)
bDirty = TRUE;
}
if (bDirty)
{
m_prs->SetFieldFlags(nField, AFX_SQL_FIELD_FLAG_DIRTY,
m_nFieldType);
}
}
#ifdef _DEBUG
// Field address must not change - ODBC's SQLBindCol depends upon this
void* pvSaved;
m_par->Read(&pvSaved, sizeof(pvSaved));
if (pvSaved != pv)
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif //_DEBUG
if ((m_pvField == NULL || m_pvField == pv) &&
m_prs->IsFieldFlagDirty(nField,
m_nFieldType))
{
m_bField = TRUE;
}
}
return;
case StoreField:
*m_par << m_prs->GetFieldFlags(nField);
if (!m_prs->IsFieldFlagNull(nField, m_nFieldType))
{
UINT nLength = cbValue;
m_par->Write(&nLength, sizeof(nLength));
m_par->Write(pv, nLength);
}
#ifdef _DEBUG
m_par->Write(&pv, sizeof(pv)); // Save field address
#endif
return;
case LoadField:
{
BYTE bFlags;
*m_par >> bFlags;
m_prs->SetFieldFlags(nField, bFlags,
m_nFieldType);
if (!m_prs->IsFieldFlagNull(nField,
m_nFieldType))
{
UINT nLength;
m_par->Read(&nLength, sizeof(nLength));
*plLength = nLength;
m_par->Read(pv, nLength);
}
else
*plLength = SQL_NULL_DATA;
#ifdef _DEBUG
// Field address must not change - ODBC's SQLBindCol depends upon this
void* pvSaved;
m_par->Read(&pvSaved, sizeof(pvSaved));
if (pvSaved != pv)
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif //_DEBUG
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)
{
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->GetFieldLength(pFX);
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,
SQL_PARAM_INPUT, SQL_C_CHAR, (SWORD)nColumnType,
nMaxLength, 0, pvParam, 0, plLength));
value.ReleaseBuffer();
if (nRetCode != SQL_SUCCESS)
pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
}
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::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
value.ReleaseBuffer();
goto LFieldFound;
}
value.ReleaseBuffer();
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_TEXT;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
value.ReleaseBuffer();
pFX->m_pfi->dwSize = nMaxLength;
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
return;
case CFieldExchange::BindFieldToColumn:
{
UINT cbColumn;
int nSqlType = pFX->GetColumnType(nField, &cbColumn);
switch (nSqlType)
{
default:
#ifdef _DEBUG
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: CString converted from SQL type %ld.\n",
nSqlType);
#endif
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;
}
// Determine string pre-allocation size
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);
}
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->SetFieldFlags(nField, AFX_SQL_FIELD_FLAG_NULL,
pFX->m_nFieldType);
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)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
// Set string 0 length
value.GetBufferSetLength(0);
value.ReleaseBuffer();
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
*plLength = SQL_NTS;
}
#ifdef _DEBUG
pFX->m_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::SetFieldDirty:
case CFieldExchange::IsFieldDirty:
case CFieldExchange::IsFieldNull:
case CFieldExchange::IsFieldNullable:
// pv arg should be &value instead of GetBuffer for these calls
pFX->Default(szName, &value, plLength,
SQL_C_CHAR, sizeof(value), sizeof(value));
return;
#ifdef _UNICODE
case CFieldExchange::NameValue:
if (pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
*pFX->m_pstr += szName;
*pFX->m_pstr += '=';
}
// Fall through
case CFieldExchange::Value:
if (pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
LPSTR lpszData = (LPSTR)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pFX->m_prs->IsFieldFlagNull(nField, pFX->m_nFieldType))
{
*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, (SWORD)nColumnType, nMaxLength, 0,
lpszData, 0, plLength));
}
}
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->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
if (!value.IsEmpty())
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
}
return;
case CFieldExchange::MarkForUpdate:
{
if (value.IsEmpty())
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
else
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
BYTE bFlags;
*pFX->m_par >> bFlags;
if ((bFlags & AFX_SQL_FIELD_FLAG_NULL))
{
if (!pFX->m_prs->IsFieldFlagNull(nField,
pFX->m_nFieldType))
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
}
}
else
{
// Saved field is not NULL. current field null, so field dirty
BOOL bDirty = pFX->m_prs->IsFieldFlagNull(nField,
pFX->m_nFieldType);
CString valueSaved;
*pFX->m_par >> valueSaved;
if (bDirty || value.Compare(valueSaved) != 0)
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
}
#ifdef _DEBUG
// Buffer address must not change - ODBC's SQLBindCol depends upon this
TCHAR* pchSaved;
pFX->m_par->Read(&pchSaved, sizeof(pchSaved));
if (pchSaved != value.GetBuffer(0))
{
TRACE1("Error: CString buffer (column %u) address has changed!\n",
nField);
ASSERT(FALSE);
}
value.ReleaseBuffer();
#endif //_DEBUG
if ((pFX->m_pvField == NULL || pFX->m_pvField == &value) &&
pFX->m_prs->IsFieldFlagDirty(nField,
pFX->m_nFieldType))
{
pFX->m_bField = TRUE;
}
}
return;
case CFieldExchange::StoreField:
{
*pFX->m_par << pFX->m_prs->GetFieldFlags(nField);
if (!pFX->m_prs->IsFieldFlagNull(nField, pFX->m_nFieldType))
*pFX->m_par << value;
#ifdef _DEBUG
// Save address of character buffer
TCHAR* pch = value.GetBuffer(0);
pFX->m_par->Write(&pch, sizeof(pch));
value.ReleaseBuffer();
#endif //_DEBUG
}
return;
case CFieldExchange::LoadField:
{
BYTE bFlags;
*pFX->m_par >> bFlags;
pFX->m_prs->SetFieldFlags(nField, bFlags,
pFX->m_nFieldType);
if (!pFX->m_prs->IsFieldFlagNull(nField,
pFX->m_nFieldType))
{
CString strT;
*pFX->m_par >> strT;
value = strT;
*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
TCHAR* pchSaved;
pFX->m_par->Read(&pchSaved, sizeof(pchSaved));
if (pchSaved != value.GetBuffer(0))
{
TRACE1("Error: CString buffer (column %u) address has changed!\n",
nField);
ASSERT(FALSE);
}
value.ReleaseBuffer();
#endif //_DEBUG
}
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->GetFieldLength(pFX);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
int nSqlType = pFX->GetColumnType(nField);
if (nSqlType != SQL_C_SHORT)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: int converted from SQL type %ld.\n",
nSqlType);
}
#endif
}
// 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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
value = AFX_RFX_INT_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
*plLength = sizeof(value);
}
#ifdef _DEBUG
pFX->m_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
if (value != AFX_RFX_INT_PSEUDO_NULL)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value != AFX_RFX_INT_PSEUDO_NULL)
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
goto LDefault;
case CFieldExchange::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
goto LFieldFound;
}
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_INT;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
pFX->m_pfi->dwSize = sizeof(value);
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
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->GetFieldLength(pFX);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
int nSqlType = pFX->GetColumnType(nField);
if (nSqlType != SQL_C_LONG)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: long converted from SQL type %ld.\n",
nSqlType);
}
#endif
}
// 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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
value = AFX_RFX_LONG_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
*plLength = sizeof(value);
}
#ifdef _DEBUG
pFX->m_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
if (value != AFX_RFX_LONG_PSEUDO_NULL)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value != AFX_RFX_LONG_PSEUDO_NULL)
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
goto LDefault;
case CFieldExchange::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
goto LFieldFound;
}
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_LONG;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
pFX->m_pfi->dwSize = sizeof(value);
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
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->GetFieldLength(pFX);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
int nSqlType = pFX->GetColumnType(nField);
if (nSqlType != SQL_TINYINT)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: BYTE converted from SQL type %ld.\n",
nSqlType);
}
#endif
}
// 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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
value = AFX_RFX_BYTE_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
*plLength = sizeof(value);
}
#ifdef _DEBUG
pFX->m_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
if (value != AFX_RFX_BYTE_PSEUDO_NULL)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value != AFX_RFX_BYTE_PSEUDO_NULL)
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
goto LDefault;
case CFieldExchange::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
goto LFieldFound;
}
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_BYTE;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
pFX->m_pfi->dwSize = sizeof(value);
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
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->GetFieldLength(pFX);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
int nSqlType = pFX->GetColumnType(nField);
if (nSqlType != SQL_BIT)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: BOOL converted from SQL type %ld.\n",
nSqlType);
}
#endif
}
// 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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
value = AFX_RFX_BOOL_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
*plLength = sizeof(value);
}
#ifdef _DEBUG
pFX->m_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
if (value != AFX_RFX_BOOL_PSEUDO_NULL)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value != AFX_RFX_BOOL_PSEUDO_NULL)
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
goto LDefault;
case CFieldExchange::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
goto LFieldFound;
}
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_BOOL;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
pFX->m_pfi->dwSize = sizeof(value);
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
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->GetFieldLength(pFX);
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:
{
UINT cbColumn;
int nSqlType = pFX->GetColumnType(nField, &cbColumn);
#ifdef _DEBUG
if (nSqlType != SQL_BINARY && nSqlType != SQL_VARBINARY &&
nSqlType != SQL_LONGVARBINARY)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: CByteArray converted from SQL type %ld.\n",
nSqlType);
}
#endif
// 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);
}
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
value.SetSize(1);
value[0] = AFX_RFX_BYTE_PSEUDO_NULL;
}
else
{
ASSERT(*plLength <= (LONG)nMaxLength);
((CDBByteArray&)value).SetLength((UINT)*plLength);
}
return;
case CFieldExchange::SetFieldDirty:
case CFieldExchange::IsFieldDirty:
case CFieldExchange::IsFieldNull:
case CFieldExchange::IsFieldNullable:
pFX->Default(szName,
&value, plLength, SQL_C_BINARY, sizeof(value), sizeof(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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
value.SetSize(1);
value[0] = AFX_RFX_BYTE_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
*plLength = value.GetSize();
}
#ifdef _DEBUG
pFX->m_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
if (value.GetSize() != 1 || value[0] != AFX_RFX_BYTE_PSEUDO_NULL)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
}
return;
case CFieldExchange::MarkForUpdate:
if (value.GetSize() != 1 || value[0] != AFX_RFX_BYTE_PSEUDO_NULL)
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
goto LDefault;
case CFieldExchange::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
goto LFieldFound;
}
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_BINARY;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
pFX->m_pfi->dwSize = nMaxLength;
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
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->GetFieldLength(pFX);
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->IsFieldFlagNull(nField, CFieldExchange::param))
{
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,
SQL_PARAM_INPUT, SQL_C_TIMESTAMP, SQL_C_TIMESTAMP,
TIMESTAMP_PRECISION, 0, pts, 0, plLength));
if (nRetCode != SQL_SUCCESS)
pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
}
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
int nSqlType = pFX->GetColumnType(nField);
if (nSqlType != SQL_DATE && nSqlType != SQL_TIME &&
nSqlType != SQL_TIMESTAMP)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: CTime converted from SQL type %ld.\n",
nSqlType);
}
#endif
// 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);
}
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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
*pFX->m_pstr += szName;
*pFX->m_pstr += '=';
}
// Fall through
case CFieldExchange::Value:
if (pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pFX->m_prs->IsFieldFlagNull(nField, pFX->m_nFieldType))
{
*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++;
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
(UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
SQL_C_TIMESTAMP, (SWORD)pFX->GetColumnType(nField),
TIMESTAMP_PRECISION, 0, pts, 0, 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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
value = AFX_RFX_DATE_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
*plLength = sizeof(TIMESTAMP_STRUCT);
}
#ifdef _DEBUG
pFX->m_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
CTime timeNull = AFX_RFX_DATE_PSEUDO_NULL;
if (value != timeNull)
{
pFX->m_prs->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
}
return;
case CFieldExchange::MarkForUpdate:
{
CTime timeNull = AFX_RFX_DATE_PSEUDO_NULL;
if (value != timeNull)
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
goto LDefault;
case CFieldExchange::LoadField:
{
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
BYTE bFlags;
*pFX->m_par >> bFlags;
pFX->m_prs->SetFieldFlags(nField, bFlags,
pFX->m_nFieldType);
if (!pFX->m_prs->IsFieldFlagNull(nField,
pFX->m_nFieldType))
{
UINT nLength;
pFX->m_par->Read(&nLength, sizeof(nLength));
*plLength = sizeof(TIMESTAMP_STRUCT);
*pFX->m_par >> value;
// Must restore proxy for correct WHERE CURRENT OF operations
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
// Field address must not change - ODBC's SQLBindCol depends upon this
void* pvSaved;
pFX->m_par->Read(&pvSaved, sizeof(pvSaved));
if (pvSaved != &value)
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif //_DEBUG
}
return;
case CFieldExchange::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
goto LFieldFound;
}
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_DATE;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
pFX->m_pfi->dwSize = sizeof(value);
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
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->GetFieldLength(pFX);
switch (pFX->m_nOperation)
{
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
int nSqlType = pFX->GetColumnType(nField);
if (nSqlType != SQL_DATE && nSqlType != SQL_TIME &&
nSqlType != SQL_TIMESTAMP)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: TIMESTAMP_STRUCT converted from SQL type %ld.\n",
nSqlType);
}
#endif
// 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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
*plLength = sizeof(TIMESTAMP_STRUCT);
}
#ifdef _DEBUG
pFX->m_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
// can force writing of psuedo-null value (as a non-null) by setting field dirty
if (!pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_DIRTY, pFX->m_nFieldType);
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
}
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->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
}
goto LDefault;
case CFieldExchange::StoreField:
{
*pFX->m_par << pFX->m_prs->GetFieldFlags(nField);
if (!pFX->m_prs->IsFieldFlagNull(nField, pFX->m_nFieldType))
{
UINT nLength = sizeof(TIMESTAMP_STRUCT);
pFX->m_par->Write(&nLength, sizeof(nLength));
pFX->m_par->Write(&value.year, sizeof(value.year));
pFX->m_par->Write(&value.month, sizeof(value.month));
pFX->m_par->Write(&value.day, sizeof(value.day));
pFX->m_par->Write(&value.hour, sizeof(value.hour));
pFX->m_par->Write(&value.minute, sizeof(value.minute));
pFX->m_par->Write(&value.second, sizeof(value.second));
pFX->m_par->Write(&value.fraction, sizeof(value.fraction));
}
#ifdef _DEBUG
TIMESTAMP_STRUCT *pts = &value;
pFX->m_par->Write(&pts, sizeof(pts)); // Save field address
#endif
}
return;
case CFieldExchange::LoadField:
{
BYTE bFlags;
*pFX->m_par >> bFlags;
pFX->m_prs->SetFieldFlags(nField, bFlags, pFX->m_nFieldType);
if (!pFX->m_prs->IsFieldFlagNull(nField,
pFX->m_nFieldType))
{
UINT nLength;
pFX->m_par->Read(&nLength, sizeof(nLength));
*plLength = nLength;
pFX->m_par->Read(&value.year, sizeof(value.year));
pFX->m_par->Read(&value.month, sizeof(value.month));
pFX->m_par->Read(&value.day, sizeof(value.day));
pFX->m_par->Read(&value.hour, sizeof(value.hour));
pFX->m_par->Read(&value.minute, sizeof(value.minute));
pFX->m_par->Read(&value.second, sizeof(value.second));
pFX->m_par->Read(&value.fraction, sizeof(value.fraction));
}
else
*plLength = SQL_NULL_DATA;
#ifdef _DEBUG
// Field address must not change - ODBC's SQLBindCol depends upon this
void* pvSaved;
pFX->m_par->Read(&pvSaved, sizeof(pvSaved));
if (pvSaved != &value)
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif //_DEBUG
}
return;
case CFieldExchange::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
goto LFieldFound;
}
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_DATE;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
pFX->m_pfi->dwSize = sizeof(value);
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
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->GetFieldLength(pFX);
switch (pFX->m_nOperation)
{
case CFieldExchange::Name:
pFX->m_prs->m_bLongBinaryColumns = TRUE;
// Fall Through
case CFieldExchange::IsFieldNull:
case CFieldExchange::IsFieldDirty:
case CFieldExchange::SetFieldDirty:
case CFieldExchange::IsFieldNullable:
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);
}
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->SetFieldFlags(nField, AFX_SQL_FIELD_FLAG_NULL,
pFX->m_nFieldType);
}
else
{
// Field not NULL, clear the status (length already set)
pFX->m_prs->ClearFieldFlags(nField, AFX_SQL_FIELD_FLAG_NULL,
pFX->m_nFieldType);
}
return;
case CFieldExchange::NameValue:
if (pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
*pFX->m_pstr += szName;
*pFX->m_pstr += '=';
}
// Fall through
case CFieldExchange::Value:
if (pFX->m_prs->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
// If user marked column NULL, reflect this in length
if (pFX->m_prs->IsFieldFlagNull(nField, pFX->m_nFieldType))
*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++;
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
(UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
SQL_C_DEFAULT, (SWORD)pFX->GetColumnType(nField),
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->IsFieldFlagDirty(nField, pFX->m_nFieldType))
{
// If user marked column NULL, reflect this in length
if (pFX->m_prs->IsFieldFlagNull(nField, pFX->m_nFieldType))
*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->SetFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
value.m_dwDataLength = 0;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearFieldFlags(nField,
AFX_SQL_FIELD_FLAG_NULL, pFX->m_nFieldType);
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_bFieldFound = TRUE;
#endif
}
return;
case CFieldExchange::GetFieldInfoValue:
if (pFX->m_pfi->pv == &value)
{
pFX->m_pfi->nField = nField-1;
goto LFieldFound;
}
return;
case CFieldExchange::GetFieldInfoOrdinal:
if (nField-1 == pFX->m_pfi->nField)
{
LFieldFound:
pFX->m_pfi->nDataType = AFX_RFX_LONGBINARY;
pFX->m_pfi->strName = szName;
pFX->m_pfi->pv = &value;
pFX->m_pfi->dwSize = sizeof(value);
// Make sure field found only once
ASSERT(pFX->m_bFieldFound == FALSE);
pFX->m_bFieldFound = TRUE;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = ";
value.Dump(*pFX->m_pdcDump);
return;
#endif //_DEBUG
}
}
int CFieldExchange::GetColumnType(int nColumn, UINT* pcbColumn,
int* pnScale, int* pnNullable)
{
ASSERT(AfxIsValidAddress(this, sizeof(CFieldExchange)));
ASSERT(pcbColumn == NULL || AfxIsValidAddress(pcbColumn, sizeof(UINT)));
ASSERT(pnScale == NULL || AfxIsValidAddress(pnScale, sizeof(int)));
ASSERT(pnNullable == NULL || AfxIsValidAddress(pnNullable, sizeof(int)));
RETCODE nRetCode;
SWORD nNameLength = 0;
SWORD nSqlType;
UDWORD dwTemp;
#ifdef _DEBUG
SWORD nResultColumns;
AFX_SQL_ASYNC(m_prs, ::SQLNumResultCols(m_prs->m_hstmt, &nResultColumns));
ASSERT(nColumn >= 1 && (long)nColumn <= (long)nResultColumns);
#endif //_DEBUG
SWORD nScale, nNullable;
AFX_SQL_ASYNC(m_prs, ::SQLDescribeCol(m_prs->m_hstmt, (UWORD)nColumn,
NULL, 0, &nNameLength, &nSqlType, &dwTemp, &nScale, &nNullable));
if (!m_prs->Check(nRetCode))
m_prs->ThrowDBException(nRetCode);
// copy from temporaries
if (pnScale != NULL)
*pnScale = nScale;
if (pnNullable != NULL)
*pnNullable = nNullable;
if (pcbColumn != NULL)
*pcbColumn = (UINT)dwTemp;
return nSqlType;
}
long CFieldExchange::GetLongBinarySize(int nField)
{
RETCODE nRetCode;
int nDummy;
long lSize;
// Give empty buffer to find size of entire LongBinary
AFX_SQL_ASYNC(m_prs, ::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_SQL_ASYNC(m_prs, ::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->SetFieldFlags(nField, AFX_SQL_FIELD_FLAG_NULL,
m_nFieldType);
*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:
#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);
// 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();
}
#endif // _DEBUG
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;
}
//////////////////////////////////////////////////////////////////////////////
// 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
/////////////////////////////////////////////////////////////////////////////