#include "stdafx.h" #include "DBFRecordset.h" #include "DBFException.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // CDBFRecordset IMPLEMENT_DYNAMIC(CDBFRecordset, CObject ) CDBFRecordset::CDBFRecordset(CDBFTableDef* pDBFTable) { m_pTableDef = NULL; m_nCurTableRecN = -1; m_bBOF = TRUE; m_bEOF = TRUE; m_pData = NULL; m_nLockMode = DbfUtility::LockPessimistic; m_nLockType = DbfUtility::NoLock; m_nEditMode = DbfUtility::noMode; } CDBFRecordset::~CDBFRecordset() { if (IsOpen()) Close(); } BOOL CDBFRecordset::Open(LPCTSTR lpszFileName, UINT nOpenFlag) { CString strFileName; if(lpszFileName == NULL) strFileName = GetDefaultDBName(); else strFileName = lpszFileName; if (strFileName.GetLength() < 4) return FALSE; // Re-Opening is invalid. if (IsOpen()) { return FALSE; } m_pTableDef = new CDBFTableDef; m_pTableDef->m_bOpen = FALSE; m_pTableDef->Open(strFileName, nOpenFlag); if(!IsOpen()) return FALSE; m_DBFFields = m_pTableDef->m_DBFFields; if(m_pTableDef->GetRecordCount() > 0) MoveFirst(); else m_nCurTableRecN = 0; return m_pTableDef->m_bOpen; } void CDBFRecordset::Close() { if (IsOpen()) m_pTableDef->Close(); m_nEditMode = DbfUtility::noMode; m_nCurTableRecN = -1; m_bBOF = TRUE; m_bEOF = TRUE; if(m_pTableDef != NULL) { delete m_pTableDef; m_pTableDef = NULL; m_DBFFields.m_pFields = NULL; m_DBFFields.m_pCurRec = NULL; } if(m_pData != NULL) { delete[] m_pData; m_pData = NULL; } } CString CDBFRecordset::GetDefaultDBName() { // Override and add UNC path to .DBF file return _T(""); } BOOL CDBFRecordset::IsBOF() const { return m_bBOF; } BOOL CDBFRecordset::IsEOF() const { return m_bEOF; } BOOL CDBFRecordset::IsDeleted() const { assert(IsOpen()); return (m_DBFFields.m_pCurRec[0] == REC_FLAG_DELETED); } CTDbfString CDBFRecordset::GetName() { assert(IsOpen()); return m_pTableDef->GetName(); } CTDbfString CDBFRecordset::GetDBFilePath() { assert(IsOpen()); return m_pTableDef->GetDBFilePath(); } CTime CDBFRecordset::GetDateCreated() { assert(IsOpen()); return m_pTableDef->GetDateCreated(); } CTime CDBFRecordset::GetDateLastUpdated() { assert(IsOpen()); return m_pTableDef->GetDateLastUpdated(); } long CDBFRecordset::GetRecordCount() { assert(IsOpen()); return m_pTableDef->GetRecordCount(); } short CDBFRecordset::GetFieldCount() { assert(IsOpen()); return m_DBFFields.GetFieldCount(); } long CDBFRecordset::GetAbsolutePosition() { assert(IsOpen()); return m_nCurTableRecN; } void CDBFRecordset::SetAbsolutePosition(long lPosition) { assert(IsOpen()); if (lPosition<0 || lPosition>=GetRecordCount()) return; DBF_LONG lTableRecN = lPosition; // Call Move. m_pTableDef->ReadRecord(lTableRecN, m_DBFFields.m_pCurRec); m_nCurTableRecN = lTableRecN; m_bBOF = m_bEOF = FALSE; } void CDBFRecordset::MoveNext() { if (IsEOF()) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lTableRecN = m_nCurTableRecN; lTableRecN++; if(lTableRecN < GetRecordCount()) { // Call Move. m_pTableDef->ReadRecord(lTableRecN, m_DBFFields.m_pCurRec); m_nCurTableRecN = lTableRecN; m_bBOF = m_bEOF = FALSE; } else { m_bEOF = TRUE; m_bBOF = GetRecordCount() > 0; } } void CDBFRecordset::MovePrev() { if (IsBOF()) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lTableRecN = m_nCurTableRecN; lTableRecN--; if(lTableRecN >= 0) { // Call Move. m_pTableDef->ReadRecord(lTableRecN, m_DBFFields.m_pCurRec); m_nCurTableRecN = lTableRecN; m_bBOF = m_bEOF = FALSE; } else { m_bBOF = TRUE; m_bEOF = GetRecordCount() > 0; } } void CDBFRecordset::MoveFirst() { if (GetRecordCount() < 1) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lTableRecN = 0; // Call Move. m_pTableDef->ReadRecord(lTableRecN, m_DBFFields.m_pCurRec); m_nCurTableRecN = lTableRecN; m_bBOF = m_bEOF = FALSE; } void CDBFRecordset::MoveLast() { if (GetRecordCount() < 1) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lTableRecN = GetRecordCount() - 1; // Call Move. m_pTableDef->ReadRecord(lTableRecN, m_DBFFields.m_pCurRec); m_nCurTableRecN = lTableRecN; m_bBOF = m_bEOF = FALSE; } void CDBFRecordset::Move(long lOffsetRec) { if (GetRecordCount() < 1) return; m_nEditMode = DbfUtility::noMode; DBF_LONG lTableRecN = /*m_nCurTableRecN + */lOffsetRec; if(lOffsetRec < 0) { if(lTableRecN < 0) { lTableRecN = 0; m_bBOF = TRUE; } else m_bBOF = FALSE; m_bEOF = FALSE; } else if(lOffsetRec > 0) { if(lTableRecN >= GetRecordCount()) { lTableRecN = GetRecordCount() - 1; m_bEOF = TRUE; } else m_bEOF = FALSE; m_bBOF = FALSE; } // Call Move. m_pTableDef->ReadRecord(lTableRecN, m_DBFFields.m_pCurRec); m_nCurTableRecN = lTableRecN; } void CDBFRecordset::CancelUpdate() { assert(IsOpen()); if (m_nEditMode == DbfUtility::noMode) return; m_pTableDef->ReadRecord(m_nCurTableRecN, m_DBFFields.m_pCurRec); m_nEditMode = DbfUtility::noMode; } BOOL CDBFRecordset::LockRecord() { assert(IsOpen()); if (m_nEditMode != DbfUtility::noMode) return FALSE; if(!(m_nOpenType & TG_DBF_USE_EXCLUSIVE)) { switch(m_nLockType) { case DbfUtility::LockDBase: { // 0xEFFFFFFFL - rec number QWORD offset = 0xEFFFFFFFL - m_nCurTableRecN; QWORD range = 1; return::LockFile((HANDLE)m_pTableDef->m_DBFile.m_hFile, LODWORD(offset), HIDWORD(offset), LODWORD(range), HIDWORD(range)); } case DbfUtility::LockClipper: { // 0x40000000L + rec number QWORD offset = 1000000000 + (m_nCurTableRecN + 1); QWORD range = 1; return::LockFile((HANDLE)m_pTableDef->m_DBFile.m_hFile, LODWORD(offset), HIDWORD(offset), LODWORD(range), HIDWORD(range)); } case DbfUtility::LockFoxpro: { // 0x40000000L + rec offset QWORD offset = 0x40000000L +/* m_pTableDef->m_DBFHead.data_offset +*/ m_pTableDef->m_DBFHead.rec_size * m_nCurTableRecN; QWORD range = 1; return::LockFile((HANDLE)m_pTableDef->m_DBFile.m_hFile, LODWORD(offset), HIDWORD(offset), LODWORD(range), HIDWORD(range)); } } } return TRUE; } BOOL CDBFRecordset::UnlockRecord() { if (IsBOF() || IsEOF() || m_nEditMode != DbfUtility::noMode) return FALSE; if(!(m_nOpenType & TG_DBF_USE_EXCLUSIVE)) { switch(m_nLockType) { case DbfUtility::LockDBase: { // 0xEFFFFFFFL - rec number QWORD offset = 0xEFFFFFFFL - m_nCurTableRecN; QWORD range = 1; return::UnlockFile((HANDLE)m_pTableDef->m_DBFile.m_hFile, LODWORD(offset), HIDWORD(offset), LODWORD(range), HIDWORD(range)); } case DbfUtility::LockClipper: { // 0x40000000L + rec number QWORD offset = 1000000000 + (m_nCurTableRecN + 1); QWORD range = 1; return::UnlockFile((HANDLE)m_pTableDef->m_DBFile.m_hFile, LODWORD(offset), HIDWORD(offset), LODWORD(range), HIDWORD(range)); } case DbfUtility::LockFoxpro: { // 0x40000000L + rec offset QWORD offset = 0x40000000L +/* m_pTableDef->m_DBFHead.data_offset +*/ m_pTableDef->m_DBFHead.rec_size * m_nCurTableRecN; QWORD range = 1; return::UnlockFile((HANDLE)m_pTableDef->m_DBFile.m_hFile, LODWORD(offset), HIDWORD(offset), LODWORD(range), HIDWORD(range)); } } } return TRUE; } void CDBFRecordset::AddNew() { assert(IsOpen()); m_nEditMode = DbfUtility::addnew; memset(m_DBFFields.m_pCurRec, 0, m_pTableDef->m_DBFHead.rec_size); COleVariant varEmpty; varEmpty.Clear(); for(short i = 0; i < m_DBFFields.GetFieldCount(); i++) { FIELD_REC* pFieldRec = m_DBFFields.GetFieldRec(i); TGSetFieldValue(m_DBFFields.m_pCurRec, pFieldRec, varEmpty); } m_DBFFields.m_pCurRec[0] = REC_FLAG_NORMAL; } void CDBFRecordset::Edit() { assert(IsOpen()); m_nEditMode = DbfUtility::edit; } void CDBFRecordset::Update() { assert(IsOpen()); if (m_nEditMode == DbfUtility::noMode) return; switch(m_nEditMode) { case DbfUtility::edit: { m_pTableDef->ReadHeader(); m_pTableDef->WriteRecord(m_nCurTableRecN, m_DBFFields.m_pCurRec); // m_pTableDef->WriteHeader(); break; } case DbfUtility::addnew: { m_pTableDef->ReadHeader(); m_pTableDef->m_DBFHead.last_rec++; m_nCurTableRecN = max(0,GetRecordCount() - 1); m_pTableDef->WriteRecord(m_nCurTableRecN, m_DBFFields.m_pCurRec); m_pTableDef->WriteHeader(); m_bBOF = m_bEOF = FALSE; break; } } m_nEditMode = DbfUtility::noMode; } void CDBFRecordset::Delete() { assert(IsOpen()); if (m_nEditMode != DbfUtility::noMode) return; m_DBFFields.m_pCurRec[0] = REC_FLAG_DELETED; m_pTableDef->WriteRecord(m_nCurTableRecN, m_DBFFields.m_pCurRec); } void CDBFRecordset::Undelete() { assert(IsOpen()); if (m_nEditMode != DbfUtility::noMode) return; m_DBFFields.m_pCurRec[0] = REC_FLAG_NORMAL; m_pTableDef->WriteRecord(m_nCurTableRecN, m_DBFFields.m_pCurRec); } COleVariant CDBFRecordset::GetFieldValue(LPCTSTR lpszName) { COleVariant varValue; CTDbfString sKey(lpszName); GetFieldValue(sKey.toLPCSTR(), varValue); return varValue; } COleVariant CDBFRecordset::GetFieldValue(int nIndex) { COleVariant varValue; GetFieldValue(nIndex, varValue); return varValue; } long CDBFRecordset::GetFieldValue(const char* lpszName, COleVariant& varValue) { for(short nIndex = 0; _stricmp(m_DBFFields.m_pFields[nIndex].field_name, lpszName) != 0 && nIndex <= m_DBFFields.m_nFieldCount; nIndex++) {}; return GetFieldValue(nIndex, varValue); } long CDBFRecordset::GetFieldValue(LPCTSTR lpszName, CString& sVal) { COleVariant varValue; CTDbfString sKey(lpszName); long nRes = GetFieldValue(sKey.toLPCSTR(), varValue); CTDbfString sTmp; FormatString(varValue,sTmp); sVal = sTmp.toCString(); return nRes; } long CDBFRecordset::GetFieldValue(LPCTSTR lpszName,double& dVal) { COleVariant varValue; CTDbfString sKey(lpszName); long nRes = GetFieldValue(sKey.toLPCSTR(), varValue); CTDbfString sVal; FormatString(varValue,sVal); dVal = atof(sVal.toLPCSTR()); return nRes; } long CDBFRecordset::GetFieldValue(LPCTSTR lpszName,int& nVal) { COleVariant varValue; CTDbfString sKey(lpszName); long nRes = GetFieldValue(sKey.toLPCSTR(), varValue); CTDbfString sVal; FormatString(varValue,sVal); nVal = atoi(sVal.toLPCSTR()); return nRes; } long CDBFRecordset::GetFieldValue(int nIndex,CTDbfString& sVal) { COleVariant varValue; long nRes = GetFieldValue(nIndex, varValue); FormatString(varValue,sVal); return nRes; } long CDBFRecordset::GetFieldValue(int nIndex,double& dVal) { COleVariant varValue; long nRes = GetFieldValue(nIndex, varValue); CTDbfString sVal; FormatString(varValue,sVal); dVal = atof(sVal.toLPCSTR()); return nRes; } long CDBFRecordset::GetFieldValue(int nIndex,int& nVal) { COleVariant varValue; long nRes = GetFieldValue(nIndex, varValue); CTDbfString sVal; FormatString(varValue,sVal); nVal = atoi(sVal.toLPCSTR()); return nRes; } long CDBFRecordset::GetFieldValue(int nIndex, COleVariant& varValue) { assert(IsOpen()); if (nIndex > m_DBFFields.m_nFieldCount) return 0; FIELD_REC* pFieldRec = m_DBFFields.GetFieldRec(nIndex); long lLen = TGGetFieldValue(m_DBFFields.m_pCurRec, pFieldRec, varValue); switch(pFieldRec->field_type) { case FLD_TYPE_MEMO: { if(varValue.vt == VT_UI4) if(varValue.ulVal > 0) { CTDbfString strValue; m_pTableDef->ReadMemoRecord(varValue.ulVal, lLen, strValue); varValue.Clear(); varValue = strValue.toCString(); } else { lLen = 0; varValue.Clear(); varValue.vt = VT_EMPTY; } else if(varValue.vt == VT_DECIMAL) // SIX if(varValue.decVal.Lo32 > 0) { CTDbfString strValue; lLen = varValue.decVal.Hi32; m_pTableDef->ReadMemoRecord(varValue.ulVal, lLen, strValue); varValue.Clear(); varValue = strValue.toCString(); } else { lLen = 0; varValue.Clear(); varValue.vt = VT_EMPTY; } break; } case FLD_TYPE_DOUBLE: { if(pFieldRec->len_info.num_size.len == sizeof(DBF_DOUBLE)) break; } case FLD_TYPE_GENERAL: case FLD_TYPE_PICTURE: { if(m_pData != NULL) { delete[] m_pData; m_pData = NULL; } if(varValue.ulVal > 0) { m_pTableDef->ReadMemoRecord(varValue.ulVal, lLen, &m_pData); varValue.vt = VT_BYREF|VT_UI1; varValue.pbVal = m_pData; } else { lLen = 0; varValue.Clear(); varValue.vt = VT_EMPTY; } break; } } return lLen; } long CDBFRecordset::GetFieldValue( LPCTSTR lpszName,float& dVal ) { double val = 0.; long result = GetFieldValue(lpszName, val); dVal = (float)val; return result; } void CDBFRecordset::SetFieldValue(const char* lpszName, const COleVariant& varValue) { for(short nIndex = 0; _stricmp(m_DBFFields.m_pFields[nIndex].field_name, lpszName) != 0 && nIndex <= m_DBFFields.m_nFieldCount; nIndex++) {}; SetFieldValue(nIndex, varValue); } void CDBFRecordset::SetFieldValue(LPCTSTR lpszName,LPCTSTR pszVal) { if (pszVal == NULL) return; CTDbfString sVal(pszVal); CTDbfString sKey(lpszName); COleVariant varValue; varValue.vt = VT_BSTR; varValue.bstrVal = sVal.toBSTR(); SetFieldValue(sKey.toLPCSTR(),varValue); SysFreeString(varValue.bstrVal); } void CDBFRecordset::SetFieldValue(LPCTSTR lpszName,double dVal) { COleVariant varValue; varValue.vt = VT_R8; varValue.dblVal = dVal; CTDbfString sKey(lpszName); SetFieldValue(sKey.toLPCSTR(),varValue); } void CDBFRecordset::SetFieldValue(LPCTSTR lpszName,int nVal) { COleVariant varValue; varValue.vt = VT_I4; varValue.lVal = nVal; CTDbfString sKey(lpszName); SetFieldValue(sKey.toLPCSTR(),varValue); } void CDBFRecordset::SetFieldValue(int nIndex,const char* pszVal) { if (pszVal == NULL) return; CTDbfString sVal(pszVal); COleVariant varValue; varValue.vt = VT_BSTR; varValue.bstrVal = sVal.toBSTR(); SetFieldValue(nIndex,varValue); SysFreeString(varValue.bstrVal); } void CDBFRecordset::SetFieldValue(int nIndex,double dVal) { COleVariant varValue; varValue.vt = VT_R8; varValue.dblVal = dVal; SetFieldValue(nIndex,varValue); } void CDBFRecordset::SetFieldValue(int nIndex,int nVal) { COleVariant varValue; varValue.vt = VT_I4; varValue.lVal = nVal; SetFieldValue(nIndex,varValue); } void CDBFRecordset::SetFieldValue(int nIndex, const COleVariant& varValue) { assert(IsOpen()); if (nIndex > m_DBFFields.m_nFieldCount) return; FIELD_REC* pFieldRec = m_DBFFields.GetFieldRec(nIndex); switch(pFieldRec->field_type) { case FLD_TYPE_MEMO: { COleVariant varDBFValue; if(varValue.vt == VT_BSTR) { CTDbfString strValue = varValue.bstrVal; DBF_CHAR* pCurRec = new DBF_CHAR[m_pTableDef->m_DBFHead.rec_size]; TGGetFieldValue(m_DBFFields.m_pCurRec, pFieldRec, varDBFValue); if(varDBFValue.vt == VT_UI4) { DBF_LONG lLen = strValue.GetLength(); m_pTableDef->WriteMemoRecord(varDBFValue.ulVal, lLen, strValue); } else if(varDBFValue.vt == VT_DECIMAL) // SIX { DBF_LONG lLen = varDBFValue.decVal.Hi32 > 0 ? varDBFValue.decVal.Hi32 : strValue.GetLength(); m_pTableDef->WriteMemoRecord(varDBFValue.ulVal, lLen, strValue); varDBFValue.decVal.Hi32 = lLen; } delete[] pCurRec; TGSetFieldValue(m_DBFFields.m_pCurRec, pFieldRec, varDBFValue); } break; } case FLD_TYPE_DOUBLE: { if(pFieldRec->len_info.num_size.len == sizeof(DBF_DOUBLE)) { TGSetFieldValue(m_DBFFields.m_pCurRec, pFieldRec, varValue); break; } } case FLD_TYPE_GENERAL: case FLD_TYPE_PICTURE: { break; } default: TGSetFieldValue(m_DBFFields.m_pCurRec, pFieldRec, varValue); } } BOOL CDBFRecordset::IsOpen() const { return (m_pTableDef == NULL ? FALSE : m_pTableDef->m_bOpen); } void CDBFRecordset::ThrowDBFException(long nTGDBFError) { TGThrowDBFException(nTGDBFError); } #ifdef _DEBUG void CDBFRecordset::AssertValid() const { CObject::AssertValid(); } void CDBFRecordset::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << "\nm_nOpenType = " << m_nOpenType; dc << "\nm_nEditMode = " << m_nEditMode; dc << "\nm_nCurTableRecN = " << m_nCurTableRecN; dc << "\nm_bBOF = " << m_bBOF; dc << "\nm_bEOF = " << m_bEOF; dc << "\n"; } #endif //_DEBUG BOOL CDBFRecordset::ChangeOpenFlag(UINT nNewFlag) { assert(m_pTableDef); return m_pTableDef->ChangeOpenFlag(nNewFlag); } BOOL CDBFRecordset::FormatString(const COleVariant& varValue,CTDbfString& Val) { CString sVal(_T("")); switch(varValue.vt) { case VT_I4: { sVal.Format(_T("%d"),varValue.lVal); break; } case VT_UI1: { sVal.Format(_T("%d"),varValue.bVal); break; } case VT_I2: { sVal.Format(_T("%d"),varValue.iVal); break; } case VT_R4: { sVal.Format(_T("%f"),varValue.fltVal); break; } case VT_R8: { sVal.Format(_T("%g"),varValue.dblVal); break; } case VT_BSTR: { sVal = varValue.bstrVal; break; } case VT_UI2: { sVal.Format(_T("%d"),varValue.uiVal); break; } case VT_UI4: { sVal.Format(_T("%d"),varValue.ulVal); break; } case VT_INT: { sVal.Format(_T("%d"),varValue.intVal); break; } case VT_UINT: { sVal.Format(_T("%d"),varValue.uintVal); } default: break; } Val = sVal; return !sVal.IsEmpty(); }