// JP opened flex table

Click to See Complete Forum and Search --> : RFX_OleDateTime Fix


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


}

}

//JP added flex table