📄 dbcore.cpp
字号:
// First addnew call, cache record values
StoreFields();
}
else
{
// subsequent Edit/AddNew call. Restore values, save them again
LoadFields();
StoreFields();
}
}
SetFieldNull(NULL);
SetFieldDirty(NULL, FALSE);
m_nEditMode = addnew;
}
void CRecordset::Edit()
{
ASSERT_VALID(this);
ASSERT(m_hstmt != SQL_NULL_HSTMT);
// we can't construct an UPDATE statement w/o any columns
ASSERT(m_nFields != 0);
if (!m_bUpdatable)
ThrowDBException(AFX_SQL_ERROR_RECORDSET_READONLY);
if (m_dwOptions & useMultiRowFetch)
{
// Can't use update methods on multi-row rowset
ASSERT(FALSE);
return;
}
if (m_bEOF || m_bBOF || m_bDeleted)
{
TRACE0("Error: Edit attempt failed - not on a record.\n");
ThrowDBException(AFX_SQL_ERROR_NO_CURRENT_RECORD);
}
if ((m_nOpenType == dynaset || m_nOpenType == dynamic) &&
m_nLockMode == pessimistic)
{
RETCODE nRetCode;
AFX_ODBC_CALL(::SQLSetPos(m_hstmt, 1, SQL_POSITION,
SQL_LCK_EXCLUSIVE));
if (!Check(nRetCode))
{
TRACE0("Error: attempt to lock record failed during Edit function.\n");
ThrowDBException(nRetCode);
}
}
if (m_bCheckCacheForDirtyFields && m_nFields > 0)
{
if (m_nEditMode == noMode)
// First edit call, cache record values
StoreFields();
else
{
// subsequent Edit/AddNew call. Restore values, save them again
LoadFields();
StoreFields();
}
}
m_nEditMode = edit;
}
BOOL CRecordset::Update()
{
ASSERT_VALID(this);
ASSERT(m_hstmt != SQL_NULL_HSTMT);
if (m_dwOptions & useMultiRowFetch)
{
// Can't use update methods on multi-row rowset
ASSERT(FALSE);
return FALSE;
}
if (m_nEditMode != addnew && m_nEditMode != edit)
{
TRACE0("Error: must enter Edit or AddNew mode before updating.\n");
ThrowDBException(AFX_SQL_ERROR_ILLEGAL_MODE);
}
return UpdateInsertDelete();
}
void CRecordset::Delete()
{
ASSERT_VALID(this);
ASSERT(m_hstmt != SQL_NULL_HSTMT);
if (m_dwOptions & useMultiRowFetch)
{
// Can't use update methods on multi-row rowset
ASSERT(FALSE);
return;
}
if (m_nEditMode != noMode)
{
TRACE0("Error: attempted to delete while still in Edit or AddNew mode.\n");
ThrowDBException(AFX_SQL_ERROR_ILLEGAL_MODE);
}
UpdateInsertDelete(); // This call can't fail in delete mode (noMode)
}
void CRecordset::CancelUpdate()
{
ASSERT_VALID(this);
ASSERT(IsOpen());
if (m_nEditMode == noMode)
// Do nothing if not in edit mode
return;
else
// Reset the edit mode
m_nEditMode = noMode;
// Restore cache if necessary
if (m_bCheckCacheForDirtyFields && m_nFields > 0)
LoadFields();
}
BOOL CRecordset::FlushResultSet() const
{
RETCODE nRetCode;
AFX_ODBC_CALL(::SQLMoreResults(m_hstmt));
if (!Check(nRetCode))
{
TRACE0("Error: attempt FlushResultSet failed.\n");
AfxThrowDBException(nRetCode, m_pDatabase, m_hstmt);
}
// Reset state of cursor
((CRecordset*)this)->ResetCursor();
return nRetCode != SQL_NO_DATA_FOUND;
}
void CRecordset::GetODBCFieldInfo(LPCTSTR lpszName,
CODBCFieldInfo& fieldinfo)
{
ASSERT_VALID(this);
ASSERT(IsOpen());
ASSERT(lpszName != NULL);
// No data or no column info fetched yet
if (GetODBCFieldCount() <= 0)
{
ASSERT(FALSE);
return;
}
// Get the index of the field corresponding to name
short nField = GetFieldIndexByName(lpszName);
GetODBCFieldInfo(nField, fieldinfo);
}
void CRecordset::GetODBCFieldInfo(short nIndex,
CODBCFieldInfo& fieldinfo)
{
ASSERT_VALID(this);
ASSERT(IsOpen());
// No data or no column info fetched yet
if (GetODBCFieldCount() <= 0)
{
ASSERT(FALSE);
return;
}
// Just copy the data into the field info
CODBCFieldInfo* pInfo = &m_rgODBCFieldInfos[nIndex];
fieldinfo.m_strName = pInfo->m_strName;
fieldinfo.m_nSQLType = pInfo->m_nSQLType;
fieldinfo.m_nPrecision = pInfo->m_nPrecision;
fieldinfo.m_nScale = pInfo->m_nScale;
fieldinfo.m_nNullability = pInfo->m_nNullability;
}
void CRecordset::GetFieldValue(LPCTSTR lpszName,
CDBVariant& varValue, short nFieldType)
{
ASSERT_VALID(this);
ASSERT(IsOpen());
ASSERT(lpszName != NULL);
// No data or no column info fetched yet
if (GetODBCFieldCount() <= 0)
{
ASSERT(FALSE);
varValue.Clear();
return;
}
// Get the index of the field corresponding to name
short nField = GetFieldIndexByName(lpszName);
GetFieldValue(nField, varValue, nFieldType);
}
void CRecordset::GetFieldValue(short nIndex,
CDBVariant& varValue, short nFieldType)
{
ASSERT_VALID(this);
ASSERT(IsOpen());
// Clear the previous variant
varValue.Clear();
// No data or no column info fetched yet
if (GetODBCFieldCount() <= 0)
{
ASSERT(FALSE);
return;
}
// Convert index to 1-based and check range
nIndex++;
if (nIndex < 1 || nIndex > GetODBCFieldCount())
{
ThrowDBException(AFX_SQL_ERROR_FIELD_NOT_FOUND);
}
void* pvData = NULL;
int nLen = 0;
// Determine the default field type and get the data buffer
if (nFieldType == DEFAULT_FIELD_TYPE)
{
nFieldType =
GetDefaultFieldType(m_rgODBCFieldInfos[nIndex - 1].m_nSQLType);
}
pvData = GetDataBuffer(varValue, nFieldType, &nLen,
m_rgODBCFieldInfos[nIndex - 1].m_nSQLType,
m_rgODBCFieldInfos[nIndex - 1].m_nPrecision);
// Now can actually get the data
long nActualSize = GetData(m_pDatabase, m_hstmt, nIndex,
nFieldType, pvData, nLen,
m_rgODBCFieldInfos[nIndex - 1].m_nSQLType);
// Handle NULL data separately
if (nActualSize == SQL_NULL_DATA)
{
// Clear value and set the value NULL
varValue.Clear();
}
else
{
// May need to cleanup and call SQLGetData again if LONG_VAR data
if (nFieldType == SQL_C_CHAR)
{
GetLongCharDataAndCleanup(m_pDatabase, m_hstmt, nIndex,
nActualSize, &pvData, nLen, *varValue.m_pstring,
m_rgODBCFieldInfos[nIndex - 1].m_nSQLType);
#ifdef _UNICODE
// Now must convert string to UNICODE
LPCSTR lpszOld = (LPCSTR)varValue.m_pstring->GetBuffer(0);
CString* pStringNew = new CString(lpszOld);
delete varValue.m_pstring;
varValue.m_pstring = pStringNew;
#endif // _UNICODE
}
else if (nFieldType == SQL_C_BINARY)
{
GetLongBinaryDataAndCleanup(m_pDatabase, m_hstmt, nIndex,
nActualSize, &pvData, nLen, varValue,
m_rgODBCFieldInfos[nIndex - 1].m_nSQLType);
}
}
}
void CRecordset::GetFieldValue(LPCTSTR lpszName, CString& strValue)
{
ASSERT_VALID(this);
ASSERT(IsOpen());
ASSERT(lpszName != NULL);
// No data or no column info fetched yet
if (GetODBCFieldCount() <= 0)
{
ASSERT(FALSE);
return;
}
// Get the index of the field corresponding to name
short nField = GetFieldIndexByName(lpszName);
GetFieldValue(nField, strValue);
}
void CRecordset::GetFieldValue(short nIndex, CString& strValue)
{
ASSERT_VALID(this);
ASSERT(IsOpen());
// No data or no column info fetched yet
if (GetODBCFieldCount() <= 0)
{
ASSERT(FALSE);
return;
}
// Convert index to 1-based and check range
nIndex++;
if (nIndex < 1 || nIndex > GetODBCFieldCount())
{
ThrowDBException(AFX_SQL_ERROR_FIELD_NOT_FOUND);
}
int nLen = GetTextLen(m_rgODBCFieldInfos[nIndex - 1].m_nSQLType,
m_rgODBCFieldInfos[nIndex - 1].m_nPrecision);
#ifndef _UNICODE
CString& strData = strValue;
#else
CString strProxy;
CString& strData = strProxy;
#endif
void* pvData = strData.GetBufferSetLength(nLen);
// Now can actually get the data
long nActualSize = GetData(m_pDatabase, m_hstmt, nIndex,
SQL_C_CHAR, pvData, nLen,
m_rgODBCFieldInfos[nIndex - 1].m_nSQLType);
// Handle NULL data separately
if (nActualSize == SQL_NULL_DATA)
{
// Clear value
strValue.Empty();
}
else
{
// May need to cleanup and call SQLGetData again if necessary
GetLongCharDataAndCleanup(m_pDatabase, m_hstmt, nIndex,
nActualSize, &pvData, nLen, strData,
m_rgODBCFieldInfos[nIndex - 1].m_nSQLType);
#ifdef _UNICODE
// Now must convert string to UNICODE
strValue = (LPCSTR)strData.GetBuffer(0);
#endif // _UNIOCDE
}
}
void CRecordset::SetFieldDirty(void* pv, BOOL bDirty)
{
ASSERT_VALID(this);
int nIndex, nIndexEnd;
// If not setting all NULL, check simple case
if (pv != NULL)
{
// GetBoundFieldIndex returns 1-based index
nIndex = GetBoundFieldIndex(pv) - 1;
if (nIndex < 0)
{
// pv must be address of field member
ASSERT(FALSE);
return;
}
else
{
nIndexEnd = nIndex;
}
}
else
{
nIndex = 0;
nIndexEnd = m_nFields - 1;
}
while (nIndex <= nIndexEnd)
{
if (bDirty)
SetDirtyFieldStatus((DWORD)nIndex);
else
ClearDirtyFieldStatus((DWORD)nIndex);
nIndex++;
}
}
void CRecordset::SetFieldNull(void* pv, BOOL bNull)
{
ASSERT_VALID(this);
ASSERT(IsOpen());
ASSERT(!(m_dwOptions & useMultiRowFetch));
// If not setting all fields NULL, check simple case (param) first
if (pv != NULL)
{
// Cached index is 1-based
int nIndex = GetBoundParamIndex(pv) - 1;
if (nIndex >= 0)
{
if (bNull)
SetNullParamStatus(nIndex);
else
ClearNullParamStatus(nIndex);
return;
}
}
// Not a param, must be a field
if (m_nFields <= 0)
{
ASSERT(FALSE);
return;
}
// Need field exchange mechanism to set PSEUDO NULL values
// and to reset data lengths (especially for RFX_LongBinary)
CFieldExchange fx(CFieldExchange::SetFieldNull, this, pv);
fx.m_nFieldFound = 0;
fx.m_bField = bNull;
DoFieldExchange(&fx);
// If no field found, m_nFieldFound will still be zero
ASSERT(fx.m_nFieldFound != 0);
}
void CRecordset::SetParamNull(int nIndex, BOOL bNull)
{
ASSERT_VALID(this);
ASSERT((DWORD)nIndex < m_nParams);
// Can be called before Open, but need to alloc status arrays first
if (!IsOpen())
AllocStatusArrays();
if (bNull)
SetNullParamStatus(nIndex);
else
ClearNullParamStatus(nIndex);
return;
}
void CRecordset::SetLockingMode(UINT nLockMode)
{
if (nLockMode == pessimistic)
{
RETCODE nRetCode;
UDWORD dwTypes;
SWORD nResult;
AFX_SQL_SYNC(::SQLGetInfo(m_pDatabase->m_hdbc, SQL_LOCK_TYPES,
&dwTypes, sizeof(dwTypes), &nResult));
if (!Check(nRetCode) || !(dwTypes & SQL_LCK_EXCLUSIVE))
ThrowDBException(AFX_SQL_ERROR_LOCK_MODE_NOT_SUPPORTED);
}
m_nLockMode = nLockMode;
}
BOOL CRecordset::Requery()
{
RETCODE nRetCode;
ASSERT_VALID(this);
ASSERT(IsOpen());
// Can't requery if using direct execution
if (m_dwOptions & executeDirect)
return FALSE;
TRY
{
// Detect changes to filter and sort
if ((m_strFilter != m_strRequeryFilter) || (m_strSort != m_strRequerySort))
{
m_strRequeryFilter = m_strFilter;
m_strRequerySort = m_strSort;
Close();
if (m_strRequerySQL.IsEmpty())
return Open(m_nOpenType, NULL, m_dwOptions);
else
return Open(m_nOpenType, m_strRequerySQL, m_dwOptions);
}
else
{
// Shutdown current query, preserving buffers for performance
AFX_SQL_SYNC(::SQLFreeStmt(m_hstmt, SQL_CLOSE));
m_lOpen = AFX_RECORDSET_STATUS_CLOSED;
// Rebind date/time parameters
RebindParams(m_hstmt);
// now attempt to re-execute the SQL Query
AFX_ODBC_CALL(::SQLExecute(m_hstmt));
if (!Check(nRetCode))
{
TRACE0("Error: Requery attempt failed.\n");
ThrowDBException(nRetCode);
}
m_lOpen = AFX_RECORDSET_STATUS_OPEN;
// Reset some cursor properties and fetch first record
ResetCursor();
MoveNext();
// If EOF, then result set empty, so set BOF as well
m_bBOF = m_bEOF;
}
}
CATCH_ALL(e)
{
Close();
THROW_LAST();
}
END_CATCH_ALL
return TRUE; // all set
}
// Shutdown any pending query for CRecordset's hstmt's
void CRecordset::Cancel()
{
ASSERT_VALID(this);
ASSERT(m_hstmt != SQL_NULL_HSTMT);
::SQLCancel(m_hstmt);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -