📄 dbrfx.cpp
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 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)
{
#ifdef _DEBUG
ASSERT(nOperation >= BindParam && nOperation <= DumpField);
#endif
ASSERT_VALID(prs);
ASSERT(prs->m_hstmt != SQL_NULL_HSTMT);
m_nFieldType = (UINT) noFieldType;
m_nOperation = nOperation;
m_prs = prs;
m_pvField = pvField;
m_nFields = 0;
m_nParams = 0;
m_nParamFields = 0;
m_bField = FALSE;
m_pstr = NULL;
m_hstmt = SQL_NULL_HSTMT;
m_lDefaultLBFetchSize = 0x00010000;
m_lDefaultLBReallocSize = 0x00010000;
}
BOOL CFieldExchange::IsFieldType(UINT* pnField)
{
if (m_nFieldType == outputColumn)
{
*pnField = ++m_nFields;
// Recordset's m_nFields must match number of Fields!
ASSERT(m_nFields <= m_prs->m_nFields);
}
else
{
// Make sure SetFieldType was called
ASSERT(m_nFieldType == inputParam ||
m_nFieldType == outputParam ||
m_nFieldType == inoutParam);
*pnField = ++m_nParams;
// Recordset's m_nParams must match number of Params!
ASSERT(m_nParams <= m_prs->m_nParams);
}
if (m_nOperation == BindParam || m_nOperation == RebindParam)
{
// only valid on a param field type
return m_nFieldType != outputColumn;
}
else
{
// valid only on an outputColumn field type
return m_nFieldType == outputColumn;
}
}
// Default implementation for RFX functions
void CFieldExchange::Default(LPCTSTR szName,
void* pv, LONG* plLength, int nCType, UINT cbValue, UINT cbPrecision)
{
RETCODE nRetCode;
UINT nField = (m_nFieldType == outputColumn)? m_nFields: m_nParams;
switch (m_nOperation)
{
case BindParam:
if (m_prs->IsParamStatusNull(nField - 1))
*plLength = SQL_NULL_DATA;
else
*plLength = cbValue;
// For params, CType is same as SQL type
AFX_SQL_SYNC(::SQLBindParameter(m_hstmt, (UWORD)nField,
(SWORD)m_nFieldType, (SWORD)nCType, (SWORD)nCType, cbPrecision, 0,
pv, 0, plLength));
if (nRetCode != SQL_SUCCESS)
m_prs->ThrowDBException(nRetCode, m_hstmt);
// Add the member address to the param map
m_prs->m_mapParamIndex.SetAt(pv, (void*)nField);
return;
case RebindParam:
// Only need to reset param length
*plLength = m_prs->IsParamStatusNull(nField - 1) ? SQL_NULL_DATA : cbValue;
return;
case BindFieldForUpdate:
if (!m_prs->IsFieldStatusDirty(nField - 1))
{
// If not dirty, set length to SQL_IGNORE for SQLSetPos updates
*plLength = SQL_IGNORE;
}
else if (!m_prs->IsFieldStatusNull(nField - 1))
{
// Reset the length as it may have changed for var length fields
*plLength = cbValue;
}
return;
case UnbindFieldForUpdate:
// Reset bound length to actual length to clear SQL_IGNOREs
if (!m_prs->IsFieldStatusDirty(nField - 1))
*plLength = cbValue;
return;
case BindFieldToColumn:
AFX_SQL_SYNC(::SQLBindCol(m_prs->m_hstmt, (UWORD)nField, (SWORD)nCType,
pv, cbValue, plLength));
if (!m_prs->Check(nRetCode))
m_prs->ThrowDBException(nRetCode);
// Add the member address to the field map
m_prs->m_mapFieldIndex.SetAt(pv, (void*)nField);
return;
case Name:
if (m_prs->IsFieldStatusDirty(nField - 1))
{
// We require a name
ASSERT(lstrlen(szName) != 0);
*m_pstr += szName;
*m_pstr += m_lpszSeparator;
}
return;
case NameValue:
if (m_prs->IsFieldStatusDirty(nField - 1))
{
*m_pstr += szName;
*m_pstr += '=';
}
// Fall through
case Value:
if (m_prs->IsFieldStatusDirty(nField - 1))
{
// If user marked column NULL, reflect this in length
if (m_prs->IsFieldStatusNull(nField - 1))
*plLength = SQL_NULL_DATA;
else
*plLength = cbValue;
// If optimizing for bulk add, only need lengths set correctly
if(!(m_prs->m_dwOptions & CRecordset::optimizeBulkAdd))
{
*m_pstr += '?';
*m_pstr += m_lpszSeparator;
m_nParamFields++;
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&m_prs->m_rgODBCFieldInfos[nField - 1];
AFX_SQL_SYNC(::SQLBindParameter(m_hstmt,
(UWORD)m_nParamFields, SQL_PARAM_INPUT,
(SWORD)nCType, pODBCInfo->m_nSQLType,
pODBCInfo->m_nPrecision, pODBCInfo->m_nScale,
pv, 0, plLength));
if (nRetCode != SQL_SUCCESS)
m_prs->ThrowDBException(nRetCode, m_hstmt);
}
}
return;
case MarkForUpdate:
{
// Get the field data
CFieldInfo* pInfo = &m_prs->m_rgFieldInfos[nField - 1];
// If user changed field value from previous value, mark field dirty
if ((pInfo->m_bStatus & AFX_SQL_FIELD_FLAG_NULL))
{
if (!m_prs->IsFieldStatusNull(nField - 1))
m_prs->SetDirtyFieldStatus(nField - 1);
}
else
{
// Saved field is not NULL. current field null, so field dirty
BOOL bDirty = m_prs->IsFieldStatusNull(nField - 1);
// If values differ, then field dirty
void* pvDataCache;
if (pInfo->m_nDataType == AFX_RFX_BOOL ||
pInfo->m_nDataType == AFX_RFX_BYTE ||
pInfo->m_nDataType == AFX_RFX_INT ||
pInfo->m_nDataType == AFX_RFX_LONG ||
pInfo->m_nDataType == AFX_RFX_SINGLE)
{
// If caching data by value, pass a ref
pvDataCache = &pInfo->m_pvDataCache;
}
else
pvDataCache = pInfo->m_pvDataCache;
if (bDirty || !AfxCompareValueByRef(pv, pvDataCache, pInfo->m_nDataType))
m_prs->SetDirtyFieldStatus(nField - 1);
}
#ifdef _DEBUG
// Field address must not change - ODBC's SQLBindCol depends upon this
void* pvBind;
switch (pInfo->m_nDataType)
{
default:
pvBind = pv;
break;
case AFX_RFX_LPTSTR:
#ifdef _UNICODE
pvBind = m_prs->m_pvFieldProxy[nField-1];
#else // !_UNICODE
pvBind = pv;
#endif
break;
case AFX_RFX_TEXT:
#ifdef _UNICODE
pvBind = m_prs->m_pvFieldProxy[nField-1];
#else // !_UNICODE
{
pvBind = ((CString*)pv)->GetBuffer(0);
((CString*)pv)->ReleaseBuffer();
}
#endif
break;
case AFX_RFX_OLEDATE:
case AFX_RFX_DATE:
pvBind = m_prs->m_pvFieldProxy[nField-1];
break;
case AFX_RFX_BINARY:
pvBind = ((CByteArray*)pv)->GetData();
break;
}
if (pInfo->m_pvBindAddress != pvBind)
{
TRACE1("Error: field address (column %u) has changed!\n",
nField);
ASSERT(FALSE);
}
#endif // _DEBUG
if ((m_pvField == NULL || m_pvField == pv) &&
m_prs->IsFieldStatusDirty(nField - 1))
{
m_bField = TRUE;
}
}
return;
case StoreField:
AfxStoreField(*m_prs, nField, pv);
return;
case LoadField:
AfxLoadField(*m_prs, nField, pv, plLength);
return;
default:
ASSERT(FALSE);
}
}
void AFXAPI RFX_Text(CFieldExchange* pFX, LPCTSTR szName,
LPTSTR value, int nMaxLength, int nColumnType, short nScale)
{
ASSERT(AfxIsValidAddress(pFX, sizeof(CFieldExchange)));
ASSERT(AfxIsValidString(szName));
ASSERT(AfxIsValidAddress(value, nMaxLength));
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_CHAR, lstrlen(value), nMaxLength);
return;
case CFieldExchange::BindParam:
{
void* pvParam = value; // 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 = pFX->m_prs->IsParamStatusNull(nField - 1) ?
SQL_NULL_DATA : SQL_NTS;
AFX_SQL_SYNC(::SQLBindParameter(pFX->m_hstmt, (UWORD)nField,
(SWORD)pFX->m_nFieldType, SQL_C_CHAR, (SWORD)nColumnType,
nMaxLength, nScale, pvParam, nMaxLength, 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;
#ifdef _UNICODE
case CFieldExchange::RebindParam:
*plLength = pFX->m_prs->IsParamStatusNull(nField - 1) ?
SQL_NULL_DATA : SQL_NTS;
if (pFX->m_prs->m_nProxyParams != 0)
{
// Fill buffer (expected by SQLBindParameter) with new param data
USES_CONVERSION;
LPSTR lpszParam = (LPSTR)pFX->m_prs->m_pvParamProxy[nField-1];
lstrcpyA(lpszParam, T2A((LPCTSTR)value));
}
return;
#endif // _UNICODE
case CFieldExchange::BindFieldToColumn:
{
// Assumes all bound fields BEFORE unbound fields
CODBCFieldInfo* pODBCInfo =
&pFX->m_prs->m_rgODBCFieldInfos[nField - 1];
UINT cbColumn = pODBCInfo->m_nPrecision;
switch (pODBCInfo->m_nSQLType)
{
default:
#ifdef _DEBUG
// Warn of possible field schema mismatch
if (afxTraceFlags & traceDatabase)
TRACE1("Warning: string converted from SQL type %ld.\n",
pODBCInfo->m_nSQLType);
#endif // _DEBUG
// Add room for extra information like sign, decimal point, etc.
cbColumn += 10;
break;
case SQL_LONGVARCHAR:
case SQL_CHAR:
case SQL_VARCHAR:
break;
case SQL_FLOAT:
case SQL_REAL:
case SQL_DOUBLE:
// Add room for sign, decimal point and " E +XXX"
cbColumn += 10;
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_TINYINT:
case SQL_SMALLINT:
case SQL_INTEGER:
case SQL_BIGINT:
// Add room for sign
cbColumn += 1;
break;
}
// Constrain to user specified max length, subject to 256 byte min
if (cbColumn > (UINT)nMaxLength || cbColumn < 256)
cbColumn = nMaxLength;
// Set up binding addres
void* pvData = value; // overwritten if _UNICODE
value[cbColumn] = '\0';
#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));
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -