Dan Querciagrossa
April 24th, 1998, 01:43 PM
Markus Fischer sent me this code that fixes problems with the RFX_OleDateTime code I sent in:
void AFXAPI AfxStoreFieldCOleDateTime(CRecordset& rs, UINT nField,
COleDateTime& value)
{
// Get the field data
CFieldInfo* pInfo = &rs.m_rgFieldInfos[nField - 1];
// Cache the status
pInfo->m_bStatus = rs.GetFieldStatus(nField - 1);
// Save the data
if (!rs.IsFieldStatusNull(nField - 1))
{
//////////////////////////////////////////////////////////////////////
//////////////////////////
//////this is the original mfc code...it has a little bug in it...
//AfxCopyValueByRef(pvField, pInfo->m_pvDataCache,
// &nDummyLength, pInfo->m_nDataType);
//////////////////////////////////////////////////////////////////////
//////////////////////////
#ifdef _DEBUG
COleDateTime * pvDataCache;
pvDataCache = (COleDateTime *)pInfo->m_pvDataCache;
TRACE("StoreField: value = %d.%d.%d , pvDataCache =%d.%d.%d\n",
value.GetDay(),value.GetMonth(),value.GetYear(),
pvDataCache->GetDay(),pvDataCache->GetMonth(),pvDataCache->GetYear());
#endif
*(COleDateTime*)pInfo->m_pvDataCache = value;
}
#ifdef _DEBUG
// Cache the bind address expected by ODBC
pInfo->m_pvBindAddress = rs.m_pvFieldProxy[nField-1];
#endif
}
void AFXAPI RFX_OleDateTime(CFieldExchange* pFX, LPCTSTR szName,
COleDateTime& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
RETCODE nRetCode;
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
default:
pFX->Default(szName, &value, plLength, SQL_C_TIMESTAMP,
sizeof(value), TIMESTAMP_PRECISION);
return;
case CFieldExchange::BindParam:
{
TIMESTAMP_STRUCT* pts;
pFX->m_prs->m_bRebindParams = TRUE;
if (pFX->m_prs->IsParamStatusNull(nField - 1))
{
pts = NULL;
*plLength = SQL_NULL_DATA;
}
else
{
// Allocate proxy array if necessary
if (pFX->m_prs->m_pvParamProxy == NULL)
{
pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
memset(pFX->m_prs->m_pvParamProxy, 0,
pFX->m_prs->m_nParams*sizeof(void*));
pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
}
// Allocate TIMESTAMP_STRUCT if necessary for SQLBindParameter
if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
{
pts = new TIMESTAMP_STRUCT;
pFX->m_prs->m_pvParamProxy[nField-1] = pts;
}
else
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
*plLength = sizeof(TIMESTAMP_STRUCT);
}
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
(SWORD)pFX->m_nFieldType, SQL_C_TIMESTAMP, SQL_C_TIMESTAMP,
TIMESTAMP_PRECISION, 0, pts, 0, plLength));
if (nRetCode != SQL_SUCCESS)
pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
// Add the member address to the param map
pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
}
return;
case CFieldExchange::RebindParam:
{
*plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
SQL_NULL_DATA : sizeof(TIMESTAMP_STRUCT);
if (pFX->m_prs->m_nProxyParams != 0)
{
// Fill buffer (expected by SQLBindParameter) with new param data
TIMESTAMP_STRUCT* pts;
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
}
}
return;
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
if (pODBCInfo->m_nSQLType != SQL_DATE &&
pODBCInfo->m_nSQLType != SQL_TIME &&
pODBCInfo->m_nSQLType != SQL_TIMESTAMP)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: COleDateTime converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
// Allocate proxy array if necessary
if (pFX->m_prs->m_pvFieldProxy == NULL)
{
pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
memset(pFX->m_prs->m_pvFieldProxy, 0,
pFX->m_prs->m_nFields*sizeof(void*));
pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
}
// Allocate TIMESTAMP_STRUCT for SQLBindCol (not necessary on Requery)
if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
pFX->m_prs->m_pvFieldProxy[nField-1] = new TIMESTAMP_STRUCT;
AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
SQL_C_TIMESTAMP, pFX->m_prs->m_pvFieldProxy[nField-1],
sizeof(TIMESTAMP_STRUCT), plLength));
if (!pFX->m_prs->Check(nRetCode))
pFX->m_prs->ThrowDBException(nRetCode);
// Add the member address to the field map
pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
}
return;
case CFieldExchange::BindFieldForUpdate:
if (pFX->m_prs->m_nProxyFields != 0)
{
// Fill buffer (expected by SQLSetPos) with new field data
TIMESTAMP_STRUCT* pts;
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvFieldProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
pFX->Default(szName, (void *)pts, plLength, SQL_C_TIMESTAMP,
sizeof(TIMESTAMP_STRUCT), TIMESTAMP_PRECISION);
}
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = COleDateTime(); // AFX_RFX_DATE_PSEUDO_NULL;
}
else
{
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pts->year year > 9999)
{
// Time value out of range, return NULL
#ifdef _DEBUG
if (afxTraceFlags & traceDatabase)
TRACE0("Warning: date value out of range, returning NULL value.\n");
#endif
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = COleDateTime(); // AFX_RFX_DATE_PSEUDO_NULL;
}
else
{
#ifdef _DEBUG
if ((afxTraceFlags & traceDatabase) && pts->fraction != 0)
TRACE0("Warning: ignoring milliseconds.\n");
#endif
value = COleDateTime(pts->year, pts->month, pts->day,
pts->hour, pts->minute, pts->second);
}
}
return;
case CFieldExchange::NameValue:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
*pFX->m_pstr += szName;
*pFX->m_pstr += '=';
#ifdef _DEBUG
TRACE("Update %s\n",szName);
#endif
}
// Fall through
case CFieldExchange::Value:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pFX->m_prs->IsFieldStatusNull(nField - 1))
{
*plLength = SQL_NULL_DATA;
}
else
{
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
*plLength = sizeof(TIMESTAMP_STRUCT);
}
// If optimizing for bulk add, only need lengths & proxy set correctly
if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
{
*pFX->m_pstr += '?';
*pFX->m_pstr += pFX->m_lpszSeparator;
pFX->m_nParamFields++;
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
(UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
SQL_C_TIMESTAMP, pODBCInfo->m_nSQLType,
TIMESTAMP_PRECISION, 0, pts, 0, plLength));
}
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = COleDateTime(); // AFX_RFX_DATE_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = sizeof(TIMESTAMP_STRUCT);
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
{
// can force writing of psuedo-null value (as a non-null) by setting
field dirty
COleDateTime timeNull; // = AFX_RFX_DATE_PSEUDO_NULL;
if (value != timeNull)
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
{
COleDateTime timeNull; // = AFX_RFX_DATE_PSEUDO_NULL;
if (value != timeNull)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
void* pv = &value;
// Get the field data
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// If user changed field value from previous value, mark field dirty
if ((pInfo->m_bStatus & AFX_SQL_FIELD_FLAG_NULL))
{
if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
}
else
{
// Saved field is not NULL. current field null, so field dirty
BOOL bDirty = pFX->m_prs->IsFieldStatusNull(nField - 1);
// If values differ, then field dirty
COleDateTime * pvDataCache;
pvDataCache = (COleDateTime *)pInfo->m_pvDataCache;
#ifdef _DEBUG
TRACE("MarkForUpdate: value = %d.%d.%d , pvDataCache =%d.%d.%d\n",
value.GetDay(),value.GetMonth(),value.GetYear(),
pvDataCache->GetDay(),pvDataCache->GetMonth(),pvDataCache->GetYear());
#endif
if (bDirty || !(value == *pvDataCache))
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
////////////////////////////////////////////////////////////////////
////////////////////////////
//////this is the original mfc code...it has a little bug in it...
// if (bDirty || !AfxCompareValueByRef(pv, pvDataCache,
pInfo->m_nDataType))
// m_prs->SetDirtyFieldStatus(nField - 1);
////////////////////////////////////////////////////////////////////
////////////////////////////
}
#ifdef _DEBUG
// Field address must not change - ODBC's SQLBindCol depends upon this
if (pInfo->m_pvBindAddress != pFX->m_prs->m_pvFieldProxy[nField-1])
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
if ((pFX->m_pvField == NULL || pFX->m_pvField == pv) &&
pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
pFX->m_bField = TRUE;
}
}
return;
case CFieldExchange::StoreField:
AfxStoreFieldCOleDateTime(*pFX->m_prs, nField, value);
break;
case CFieldExchange::LoadField:
{
// Get the field data
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// Restore the status
pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus);
// If not NULL, restore the value, length and proxy
if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
{
////////////////////////////////////////////////////////////////////
////////////////////////////
//////this is the original mfc code...it has a little bug in it...
// AfxCopyValueByRef(pInfo->m_pvDataCache, &value,
// plLength, pInfo->m_nDataType);
////////////////////////////////////////////////////////////////////
////////////////////////////
*plLength = sizeof(TIMESTAMP_STRUCT);
*(COleDateTime*)pInfo->m_pvDataCache = value;
////////////////////////////////////////////////////////////////////
////////////////////////////
// Restore proxy for correct WHERE CURRENT OF operations
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
}
else
*plLength = SQL_NULL_DATA;
#ifdef _DEBUG
// Buffer address must not change - ODBC's SQLBindCol depends upon this
if (pInfo->m_pvBindAddress != pFX->m_prs->m_pvFieldProxy[nField-1])
{
TRACE1("Error: CString buffer (column %u) address has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
}
return;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
pInfo->m_pvDataCache = new COleDateTime;
pInfo->m_nDataType = AFX_RFX_DATE;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = " << value;
return;
#endif // _DEBUG
}
}
void AFXAPI AfxStoreFieldCOleDateTime(CRecordset& rs, UINT nField,
COleDateTime& value)
{
// Get the field data
CFieldInfo* pInfo = &rs.m_rgFieldInfos[nField - 1];
// Cache the status
pInfo->m_bStatus = rs.GetFieldStatus(nField - 1);
// Save the data
if (!rs.IsFieldStatusNull(nField - 1))
{
//////////////////////////////////////////////////////////////////////
//////////////////////////
//////this is the original mfc code...it has a little bug in it...
//AfxCopyValueByRef(pvField, pInfo->m_pvDataCache,
// &nDummyLength, pInfo->m_nDataType);
//////////////////////////////////////////////////////////////////////
//////////////////////////
#ifdef _DEBUG
COleDateTime * pvDataCache;
pvDataCache = (COleDateTime *)pInfo->m_pvDataCache;
TRACE("StoreField: value = %d.%d.%d , pvDataCache =%d.%d.%d\n",
value.GetDay(),value.GetMonth(),value.GetYear(),
pvDataCache->GetDay(),pvDataCache->GetMonth(),pvDataCache->GetYear());
#endif
*(COleDateTime*)pInfo->m_pvDataCache = value;
}
#ifdef _DEBUG
// Cache the bind address expected by ODBC
pInfo->m_pvBindAddress = rs.m_pvFieldProxy[nField-1];
#endif
}
void AFXAPI RFX_OleDateTime(CFieldExchange* pFX, LPCTSTR szName,
COleDateTime& value)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
RETCODE nRetCode;
UINT nField;
if (!pFX->IsFieldType(&nField))
return;
LONG* plLength = pFX->m_prs->GetFieldLengthBuffer(
nField - 1, pFX->m_nFieldType);
switch (pFX->m_nOperation)
{
default:
pFX->Default(szName, &value, plLength, SQL_C_TIMESTAMP,
sizeof(value), TIMESTAMP_PRECISION);
return;
case CFieldExchange::BindParam:
{
TIMESTAMP_STRUCT* pts;
pFX->m_prs->m_bRebindParams = TRUE;
if (pFX->m_prs->IsParamStatusNull(nField - 1))
{
pts = NULL;
*plLength = SQL_NULL_DATA;
}
else
{
// Allocate proxy array if necessary
if (pFX->m_prs->m_pvParamProxy == NULL)
{
pFX->m_prs->m_pvParamProxy = new void*[pFX->m_prs->m_nParams];
memset(pFX->m_prs->m_pvParamProxy, 0,
pFX->m_prs->m_nParams*sizeof(void*));
pFX->m_prs->m_nProxyParams = pFX->m_prs->m_nParams;
}
// Allocate TIMESTAMP_STRUCT if necessary for SQLBindParameter
if (pFX->m_prs->m_pvParamProxy[nField-1] == NULL)
{
pts = new TIMESTAMP_STRUCT;
pFX->m_prs->m_pvParamProxy[nField-1] = pts;
}
else
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
*plLength = sizeof(TIMESTAMP_STRUCT);
}
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
(SWORD)pFX->m_nFieldType, SQL_C_TIMESTAMP, SQL_C_TIMESTAMP,
TIMESTAMP_PRECISION, 0, pts, 0, plLength));
if (nRetCode != SQL_SUCCESS)
pFX->m_prs->ThrowDBException(nRetCode, pFX->m_hstmt);
// Add the member address to the param map
pFX->m_prs->m_mapParamIndex.SetAt(&value, (void*)nField);
}
return;
case CFieldExchange::RebindParam:
{
*plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
SQL_NULL_DATA : sizeof(TIMESTAMP_STRUCT);
if (pFX->m_prs->m_nProxyParams != 0)
{
// Fill buffer (expected by SQLBindParameter) with new param data
TIMESTAMP_STRUCT* pts;
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvParamProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
}
}
return;
case CFieldExchange::BindFieldToColumn:
{
#ifdef _DEBUG
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
if (pODBCInfo->m_nSQLType != SQL_DATE &&
pODBCInfo->m_nSQLType != SQL_TIME &&
pODBCInfo->m_nSQLType != SQL_TIMESTAMP)
{
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: COleDateTime converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
}
#endif // _DEBUG
// Allocate proxy array if necessary
if (pFX->m_prs->m_pvFieldProxy == NULL)
{
pFX->m_prs->m_pvFieldProxy = new void*[pFX->m_prs->m_nFields];
memset(pFX->m_prs->m_pvFieldProxy, 0,
pFX->m_prs->m_nFields*sizeof(void*));
pFX->m_prs->m_nProxyFields = pFX->m_prs->m_nFields;
}
// Allocate TIMESTAMP_STRUCT for SQLBindCol (not necessary on Requery)
if (pFX->m_prs->m_pvFieldProxy[nField-1] == NULL)
pFX->m_prs->m_pvFieldProxy[nField-1] = new TIMESTAMP_STRUCT;
AFX_SQL_SYNC(::SQLBindCol(pFX->m_prs->m_hstmt, (UWORD)nField,
SQL_C_TIMESTAMP, pFX->m_prs->m_pvFieldProxy[nField-1],
sizeof(TIMESTAMP_STRUCT), plLength));
if (!pFX->m_prs->Check(nRetCode))
pFX->m_prs->ThrowDBException(nRetCode);
// Add the member address to the field map
pFX->m_prs->m_mapFieldIndex.SetAt(&value, (void*)nField);
}
return;
case CFieldExchange::BindFieldForUpdate:
if (pFX->m_prs->m_nProxyFields != 0)
{
// Fill buffer (expected by SQLSetPos) with new field data
TIMESTAMP_STRUCT* pts;
pts = (TIMESTAMP_STRUCT *)pFX->m_prs->m_pvFieldProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
pFX->Default(szName, (void *)pts, plLength, SQL_C_TIMESTAMP,
sizeof(TIMESTAMP_STRUCT), TIMESTAMP_PRECISION);
}
return;
case CFieldExchange::Fixup:
if (*plLength == SQL_NULL_DATA)
{
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = COleDateTime(); // AFX_RFX_DATE_PSEUDO_NULL;
}
else
{
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pts->year year > 9999)
{
// Time value out of range, return NULL
#ifdef _DEBUG
if (afxTraceFlags & traceDatabase)
TRACE0("Warning: date value out of range, returning NULL value.\n");
#endif
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = COleDateTime(); // AFX_RFX_DATE_PSEUDO_NULL;
}
else
{
#ifdef _DEBUG
if ((afxTraceFlags & traceDatabase) && pts->fraction != 0)
TRACE0("Warning: ignoring milliseconds.\n");
#endif
value = COleDateTime(pts->year, pts->month, pts->day,
pts->hour, pts->minute, pts->second);
}
}
return;
case CFieldExchange::NameValue:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
*pFX->m_pstr += szName;
*pFX->m_pstr += '=';
#ifdef _DEBUG
TRACE("Update %s\n",szName);
#endif
}
// Fall through
case CFieldExchange::Value:
if (pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
if (pFX->m_prs->IsFieldStatusNull(nField - 1))
{
*plLength = SQL_NULL_DATA;
}
else
{
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
*plLength = sizeof(TIMESTAMP_STRUCT);
}
// If optimizing for bulk add, only need lengths & proxy set correctly
if(!(pFX->m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
{
*pFX->m_pstr += '?';
*pFX->m_pstr += pFX->m_lpszSeparator;
pFX->m_nParamFields++;
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt,
(UWORD)pFX->m_nParamFields, SQL_PARAM_INPUT,
SQL_C_TIMESTAMP, pODBCInfo->m_nSQLType,
TIMESTAMP_PRECISION, 0, pts, 0, plLength));
}
}
return;
case CFieldExchange::SetFieldNull:
if ((pFX->m_pvField == NULL &&
pFX->m_nFieldType == CFieldExchange::outputColumn) ||
pFX->m_pvField == &value)
{
if (pFX->m_bField)
{
// Mark fields null
pFX->m_prs->SetNullFieldStatus(nField - 1);
value = COleDateTime(); // AFX_RFX_DATE_PSEUDO_NULL;
*plLength = SQL_NULL_DATA;
}
else
{
pFX->m_prs->ClearNullFieldStatus(nField - 1);
*plLength = sizeof(TIMESTAMP_STRUCT);
}
#ifdef _DEBUG
pFX->m_nFieldFound = nField;
#endif
}
return;
case CFieldExchange::MarkForAddNew:
{
// can force writing of psuedo-null value (as a non-null) by setting
field dirty
COleDateTime timeNull; // = AFX_RFX_DATE_PSEUDO_NULL;
if (value != timeNull)
{
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
pFX->m_prs->ClearNullFieldStatus(nField - 1);
}
}
return;
case CFieldExchange::MarkForUpdate:
{
COleDateTime timeNull; // = AFX_RFX_DATE_PSEUDO_NULL;
if (value != timeNull)
pFX->m_prs->ClearNullFieldStatus(nField - 1);
void* pv = &value;
// Get the field data
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// If user changed field value from previous value, mark field dirty
if ((pInfo->m_bStatus & AFX_SQL_FIELD_FLAG_NULL))
{
if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
}
else
{
// Saved field is not NULL. current field null, so field dirty
BOOL bDirty = pFX->m_prs->IsFieldStatusNull(nField - 1);
// If values differ, then field dirty
COleDateTime * pvDataCache;
pvDataCache = (COleDateTime *)pInfo->m_pvDataCache;
#ifdef _DEBUG
TRACE("MarkForUpdate: value = %d.%d.%d , pvDataCache =%d.%d.%d\n",
value.GetDay(),value.GetMonth(),value.GetYear(),
pvDataCache->GetDay(),pvDataCache->GetMonth(),pvDataCache->GetYear());
#endif
if (bDirty || !(value == *pvDataCache))
pFX->m_prs->SetDirtyFieldStatus(nField - 1);
////////////////////////////////////////////////////////////////////
////////////////////////////
//////this is the original mfc code...it has a little bug in it...
// if (bDirty || !AfxCompareValueByRef(pv, pvDataCache,
pInfo->m_nDataType))
// m_prs->SetDirtyFieldStatus(nField - 1);
////////////////////////////////////////////////////////////////////
////////////////////////////
}
#ifdef _DEBUG
// Field address must not change - ODBC's SQLBindCol depends upon this
if (pInfo->m_pvBindAddress != pFX->m_prs->m_pvFieldProxy[nField-1])
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
if ((pFX->m_pvField == NULL || pFX->m_pvField == pv) &&
pFX->m_prs->IsFieldStatusDirty(nField - 1))
{
pFX->m_bField = TRUE;
}
}
return;
case CFieldExchange::StoreField:
AfxStoreFieldCOleDateTime(*pFX->m_prs, nField, value);
break;
case CFieldExchange::LoadField:
{
// Get the field data
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
// Restore the status
pFX->m_prs->SetFieldStatus(nField - 1, pInfo->m_bStatus);
// If not NULL, restore the value, length and proxy
if (!pFX->m_prs->IsFieldStatusNull(nField - 1))
{
////////////////////////////////////////////////////////////////////
////////////////////////////
//////this is the original mfc code...it has a little bug in it...
// AfxCopyValueByRef(pInfo->m_pvDataCache, &value,
// plLength, pInfo->m_nDataType);
////////////////////////////////////////////////////////////////////
////////////////////////////
*plLength = sizeof(TIMESTAMP_STRUCT);
*(COleDateTime*)pInfo->m_pvDataCache = value;
////////////////////////////////////////////////////////////////////
////////////////////////////
// Restore proxy for correct WHERE CURRENT OF operations
TIMESTAMP_STRUCT* pts =
(TIMESTAMP_STRUCT*)pFX->m_prs->m_pvFieldProxy[nField-1];
pts->year = (SWORD)value.GetYear();
pts->month = (UWORD)value.GetMonth();
pts->day = (UWORD)value.GetDay();
pts->hour = (UWORD)value.GetHour();
pts->minute = (UWORD)value.GetMinute();
pts->second = (UWORD)value.GetSecond();
pts->fraction = 0;
}
else
*plLength = SQL_NULL_DATA;
#ifdef _DEBUG
// Buffer address must not change - ODBC's SQLBindCol depends upon this
if (pInfo->m_pvBindAddress != pFX->m_prs->m_pvFieldProxy[nField-1])
{
TRACE1("Error: CString buffer (column %u) address has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
}
return;
case CFieldExchange::AllocCache:
{
CFieldInfo* pInfo = &pFX->m_prs->m_rgFieldInfos[nField - 1];
pInfo->m_pvDataCache = new COleDateTime;
pInfo->m_nDataType = AFX_RFX_DATE;
}
return;
#ifdef _DEBUG
case CFieldExchange::DumpField:
*pFX->m_pdcDump << "\n" << szName << " = " << value;
return;
#endif // _DEBUG
}
}