// 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 /////////////////////////////////////////////////////////////////////////////