/*++ © 1998 Seagate Software, Inc. All rights reserved. Module Name: Wsbdbent.cpp Abstract: The CWsbDbEntity and CWsbDbKey classes. Author: Ron White [ronw] 11-Dec-1996 Revision History: --*/ #include "stdafx.h" #include "wsbdbsys.h" #include "wsbdbkey.h" // Flags for binary search #define BIN_EQ 0x0001 #define BIN_GT 0x0002 #define BIN_LT 0x0004 #define BIN_GTE (BIN_EQ | BIN_GT) #define BIN_LTE (BIN_EQ | BIN_LT) // Flags for CopyValues/GetValue/SetValue functions #define EV_DERIVED_DATA 0x0001 #define EV_INDEX 0x0002 #define EV_POS 0x0004 #define EV_ASNEW 0x0008 #define EV_USEKEY 0x0010 #define EV_SEQNUM 0x0020 #define EV_ALL 0xFFFF HRESULT CWsbDbEntity::Clone( IN REFIID riid, OUT void** ppEntity ) /*++ Implements: IWsbDbEntity::Clone --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::Clone(IWsbEntity)"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CLSID clsid; CComPtr pEntity; CComPtr pEntityPriv; CComPtr pIPersistStream; IUnknown* pIUnknown; WsbAssert(0 != ppEntity, E_POINTER); // Create a new entity instance. pIUnknown = (IUnknown *)(IWsbPersistable *)(CWsbCollectable *)this; WsbAffirmHr(pIUnknown->QueryInterface(IID_IPersistStream, (void**) &pIPersistStream)); WsbAffirmHr(pIPersistStream->GetClassID(&clsid)); WsbAffirmHr(CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IWsbDbEntity, (void**) &pEntity)); WsbAffirmHr(pEntity->QueryInterface(IID_IWsbDbEntityPriv, (void**)&pEntityPriv)) // Initialize the clone if (m_pDb) { WsbAffirmHr(pEntityPriv->Init(m_pDb, m_pDbSys, m_RecInfo.Type, m_SessionId)); } // Copy data into the clone WsbAffirmHr(pEntityPriv->CopyValues(EV_ALL, this)); // Get the requested interface WsbAffirmHr(pEntity->QueryInterface(riid, (void**)ppEntity)); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::Clone(IWbEntity)"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::Copy( IWsbDbEntity* pEntity ) /*++ Implements: IWsbDbEntityPriv::Copy Comments: Copy the data in the derived object. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::Copy(IWsbDbEntity)"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { HGLOBAL hMem; CComPtr pIPersistStream1; CComPtr pIPersistStream2; CComPtr pIStream; IUnknown* pIUnknown; WsbAssert(0 != pEntity, E_POINTER); // Get PersistStream interfaces for myself pIUnknown = (IUnknown *)(IWsbPersistable *)(CWsbCollectable *)this; WsbAffirmHr(pIUnknown->QueryInterface(IID_IPersistStream, (void**) &pIPersistStream1)); WsbAffirmHr(pEntity->QueryInterface(IID_IPersistStream, (void**) &pIPersistStream2)); // Create a memory stream WsbAffirmHr(getMem(&hMem)); WsbAffirmHr(CreateStreamOnHGlobal(hMem, FALSE, &pIStream)); // Save the other entity to the stream WsbAffirmHr(pIPersistStream2->Save(pIStream, FALSE)); pIStream = 0; // Load myself from the memory WsbAffirmHr(fromMem(hMem)); GlobalFree(hMem); SetIsDirty(TRUE); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::Copy(IWbEntity)"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::CopyValues( ULONG flags, IWsbDbEntity* pEntity ) /*++ Implements: IWsbDbEntityPriv::CopyValues Comments: Selectively copy some DBEntity values from one entity to another. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::CopyValues(IWsbEntity)"), OLESTR("")); try { ULONG value; CComPtr pEntityPriv; // Copy derived data if (flags & EV_DERIVED_DATA) { WsbAffirmHr(Copy(pEntity)); } WsbAffirmHr(pEntity->QueryInterface(IID_IWsbDbEntityPriv, (void**)&pEntityPriv)); // Copy DbEntity specific data if (flags & EV_USEKEY) { WsbAffirmHr(pEntityPriv->GetValue(EV_USEKEY, &value)); if (m_pKeyInfo[m_UseKeyIndex].Type != value) { WsbAffirmHr(UseKey(value)); } } if (flags & EV_SEQNUM) { WsbAffirmHr(pEntityPriv->GetValue(EV_SEQNUM, &value)); m_SeqNum = (LONG)value; } if (flags & EV_ASNEW) { WsbAffirmHr(pEntityPriv->GetValue(EV_ASNEW, &value)); if (value) { WsbAffirmHr(MarkAsNew()); } } SetIsDirty(TRUE); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::CopyValues(IWbEntity)"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::Disconnect( void ) /*++ Implements: IWsbDbEntityPriv::Disconnect Comments: Disconnect the entity from its database (to reduce the DBs reference count). --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::Disconnect()"), OLESTR("")); try { if (m_pDb) { // WsbAffirmHr(m_pDb->Release()); m_pDb = NULL; // Release is automatic } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::Disconnect()"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::GetCurKey( IWsbDbKey** ppKey ) /*++ Implements: IWsbDbEntityPriv::GetCurKey Comments: Return the current key. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::GetCurKey"), OLESTR("")); try { ULONG kType = 0; if (m_pKeyInfo) { kType = m_pKeyInfo[m_UseKeyIndex].Type; } WsbAffirmHr(GetKey(kType, ppKey)); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::GetCurKey(IWbEntity)"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::GetKey( ULONG KeyType, IWsbDbKey** ppKey ) /*++ Implements: IWsbDbEntityPriv::GetKey Comments: Return the specified key. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::GetKey"), OLESTR("")); try { CComPtr pKey; CComPtr pKeyPriv; WsbAssert(0 != ppKey, E_POINTER); WsbAffirmHr(CoCreateInstance(CLSID_CWsbDbKey, 0, CLSCTX_SERVER, IID_IWsbDbKey, (void **)&pKey )); WsbAffirmHr(pKey->QueryInterface(IID_IWsbDbKeyPriv, (void**)&pKeyPriv)); WsbAffirmHr(pKeyPriv->SetType(KeyType)); WsbAffirmHr(UpdateKey(pKey)); *ppKey = pKey; (*ppKey)->AddRef(); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::GetKey(IWbEntity)"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::FindEQ( void ) /*++ Implements: IWsbDbEntity::FindEQ --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::FindEQ"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_seek(JET_bitSeekEQ)); WsbAffirmHr(jet_get_data()); } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::FindEQ"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::FindGT( void ) /*++ Implements: IWsbDbEntity::FindGT --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::FindGT"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_seek(JET_bitSeekGT)); WsbAffirmHr(jet_get_data()); } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::FindGT"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::FindGTE( void ) /*++ Implements: IWsbDbEntity::FindGTE --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::FindGTE"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_seek(JET_bitSeekGE)); WsbAffirmHr(jet_get_data()); } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::FindGTE"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::FindLT( void ) /*++ Implements: IWsbDbEntity::FindLT --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::FindLT"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_seek(JET_bitSeekLT)); WsbAffirmHr(jet_get_data()); } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::FindLT"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::FindLTE( void ) /*++ Implements: IWsbDbEntity::FindLTE --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::FindLTE"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_seek(JET_bitSeekLE)); WsbAffirmHr(jet_get_data()); } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::FindLTE"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::First( void ) /*++ Implements: IWsbDbEntity::First. --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::First"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_move(JET_MoveFirst)); WsbAffirmHr(jet_get_data()); m_SaveAsNew = FALSE; } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::First"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::GetValue( ULONG flag, ULONG* pValue ) /*++ Implements: IWsbDbEntityPriv::GetValue Comments: Get a specific (based on flag) value from a DBEntity. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::GetValue"), OLESTR("")); try { switch (flag) { case EV_INDEX: break; case EV_POS: break; case EV_ASNEW: *pValue = m_SaveAsNew; break; case EV_USEKEY: *pValue = m_pKeyInfo[m_UseKeyIndex].Type; break; case EV_SEQNUM: *pValue = (ULONG)m_SeqNum; break; } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::GetValue"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::SetSequentialScan( void ) /*++ Implements: IWsbDbEntity::SetSequentialScan. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::SetSequentialScan"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { JET_ERR jstat = JET_errSuccess; // Set to sequential traversing jstat = JetSetTableSequential(m_SessionId, m_TableId, 0); WsbAffirmHr(jet_error(jstat)); m_Sequential = TRUE; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::SetSequentialScan"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::ResetSequentialScan( void ) /*++ Implements: IWsbDbEntity::ResetSequentialScan. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::ResetSequentialScan"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { JET_ERR jstat = JET_errSuccess; // Set to sequential traversing jstat = JetResetTableSequential(m_SessionId, m_TableId, 0); WsbAffirmHr(jet_error(jstat)); m_Sequential = FALSE; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::ResetSequentialScan"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::Init( IN IWsbDb* pDb, IN IWsbDbSys *pDbSys, IN ULONG RecType, IN JET_SESID SessionId ) /*++ Implements: IWsbDbEntity::Init --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::Init"), OLESTR("")); try { WsbAssert(0 != pDb, E_POINTER); WsbAssert(0 != pDbSys, E_POINTER); // Don't allow DB Sys switch if (pDbSys != m_pDbSys) { m_pDbSys = pDbSys; // Automatic AddRef() on Db Sys object } // Don't allow DB switch if (pDb != m_pDb) { CComPtr pDbImp; // CComQIPtr pSessionPriv = pSession; WsbAssert(m_pDb == 0, WSB_E_INVALID_DATA); m_pDb = pDb; // Automatic AddRef() on Db object // WsbAssertHr(pSessionPriv->GetJetId(&m_Session)); // Get info about myself from the IDB object WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->GetRecInfo(RecType, &m_RecInfo)); WsbAssert(m_RecInfo.nKeys > 0, E_INVALIDARG); // Get info about my keys m_pKeyInfo = (COM_IDB_KEY_INFO*)WsbAlloc(sizeof(COM_IDB_KEY_INFO) * m_RecInfo.nKeys); WsbAffirmHr(pDbImp->GetKeyInfo(RecType, m_RecInfo.nKeys, m_pKeyInfo)); // Get the maximum amount of memory need to hold a streamed // copy of the user data // ULONG minSize; // WsbAffirmHr(pDbImp->GetRecSize(m_RecInfo.Type, &minSize, &m_RecInfo.MaxSize)); m_SeqNum = -1; m_PosOk = FALSE; m_SessionId = SessionId; // Get Jet IDs (and a new table ID unique to this entity) WsbAffirmHr(pDbImp->GetJetIds(m_SessionId, m_RecInfo.Type, &m_TableId, &m_ColId)); WsbAffirmHr(getMem(&m_hMem)); // Set the first key as the default UseKey(m_pKeyInfo[0].Type); } } WsbCatch(hr); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); WsbTraceOut(OLESTR("CWsbDbEntity::Init"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::Last( void ) /*++ Implements: IWsbDbEntity::Last. --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::Last"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_move(JET_MoveLast)); WsbAffirmHr(jet_get_data()); m_SaveAsNew = FALSE; } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::Last"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::MarkAsNew( void ) /*++ Implements: IWsbDbEntity::MarkAsNew --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::MarkAsNew"), OLESTR("")); try { m_SaveAsNew = TRUE; m_SeqNum = -1; m_PosOk = FALSE; SetIsDirty(TRUE); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::MarkAsNew"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::Next( void ) /*++ Implements: IWsbDbEntity::Next. --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::Next"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_make_current()); WsbAffirmHr(jet_move(JET_MoveNext)); WsbAffirmHr(jet_get_data()); m_SaveAsNew = FALSE; } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::Next"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::Previous( void ) /*++ Implements: IWsbDbEntity::Previous. --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::Previous"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); WsbAffirmHr(jet_make_current()); WsbAffirmHr(jet_move(JET_MovePrevious)); WsbAffirmHr(jet_get_data()); m_SaveAsNew = FALSE; } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::Previous"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::Print( IStream* pStream ) /*++ Implements: IWsbDbEntity::Print. --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::Print"), OLESTR("")); try { CComPtr pEntity; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR(" (IDB SeqNum = %6ld) "), m_SeqNum)); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::Print"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::Remove( void ) /*++ Implements: IWsbDbEntity::Remove --*/ { HRESULT hr = S_OK; CComPtr pDbImp; WsbTraceIn(OLESTR("CWsbDbEntity::Remove"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pIUn; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); JET_ERR jstat; // Make sure this record is the current record. WsbAffirmHr(jet_make_current()); // Delete the record jstat = JetDelete(m_SessionId, m_TableId); WsbAffirmHr(jet_error(jstat)); CComQIPtr pDbSysPriv = m_pDbSys; WsbAffirmPointer(pDbSysPriv); WsbAffirmHr(pDbSysPriv->IncrementChangeCount()); } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } WsbTraceOut(OLESTR("CWsbDbEntity::Remove"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::SetValue( ULONG flag, ULONG value ) /*++ Implements: IWsbDbEntityPriv::SetValue Comments: Set a specific data value (base on flag). --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::SetValue"), OLESTR("")); try { CComPtr pDbImp; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); switch (flag) { case EV_INDEX: break; case EV_POS: break; case EV_ASNEW: if (value) { m_SaveAsNew = TRUE; } else { m_SaveAsNew = FALSE; } break; case EV_USEKEY: m_pKeyInfo[m_UseKeyIndex].Type = value; break; case EV_SEQNUM: m_SeqNum = (LONG)value; break; } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::SetValue"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::UseKey( IN ULONG type ) /*++ Implements: IWsbDbEntity::UseKey --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::UseKey"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { CComPtr pDbImp; // Check that this is a valid key type for (int i = 0; i < m_RecInfo.nKeys; i++) { // Special case for type == 0; this means to use the // sequence number key if (0 == type) break; if (m_pKeyInfo[i].Type == type) break; } WsbAssert(i < m_RecInfo.nKeys, E_INVALIDARG); m_UseKeyIndex = (USHORT)i; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); size_t ilen; char * index_name_a; CWsbStringPtr index_name_w; JET_ERR jstat; WsbAffirmHr(index_name_w.Alloc(20)); WsbAffirmHr(pDbImp->GetJetIndexInfo(m_SessionId, m_RecInfo.Type, type, NULL, &index_name_w, 20)); ilen = wcslen(index_name_w); index_name_a = (char *)WsbAlloc(sizeof(WCHAR) * ilen + 1); WsbAffirm(0 != index_name_a, E_FAIL); WsbAffirm(0 < wcstombs(index_name_a, index_name_w, ilen + 1), E_FAIL); // Set the current index jstat = JetSetCurrentIndex(m_SessionId, m_TableId, index_name_a); WsbFree(index_name_a); WsbAffirmHr(jet_error(jstat)); m_PosOk = FALSE; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::UseKey"), OLESTR("")); return(hr); } HRESULT CWsbDbEntity::Write( void ) /*++ Implements: IWsbDbEntity::Write --*/ { HRESULT hr = S_OK; CComPtr pDbImp; UCHAR temp_bytes1[IDB_MAX_KEY_SIZE + 4]; WsbTraceIn(OLESTR("CWsbDbEntity::Write"), OLESTR("SaveAsNew = %ls"), WsbBoolAsString(m_SaveAsNew)); JET_ERR jstat; WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); jstat = JetBeginTransaction(m_SessionId); WsbTrace(OLESTR("CWsbDbEntity::Write: JetBeginTransaction = %ld\n"), jstat); try { CComPtr pEntity; CComPtr pEntityPriv; ULONG save_key_type; WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->Lock()); save_key_type = m_pKeyInfo[m_UseKeyIndex].Type; VOID* addr; ULONG Size; // Save the entity data to memory WsbAffirmHr(toMem(m_hMem, &Size)); // Write the data to the current record addr = GlobalLock(m_hMem); WsbAffirm(addr, E_HANDLE); if (m_SaveAsNew) { jstat = JetPrepareUpdate(m_SessionId, m_TableId, JET_prepInsert); } else { // Make sure this record is the current record. WsbAffirmHr(jet_make_current()); jstat = JetPrepareUpdate(m_SessionId, m_TableId, JET_prepReplace); } WsbAffirmHr(jet_error(jstat)); WsbTrace(OLESTR("Setting binary record data\n")); jstat = JetSetColumn(m_SessionId, m_TableId, m_ColId, addr, Size, 0, NULL); WsbAffirmHr(jet_error(jstat)); // Release the memory GlobalUnlock(m_hMem); // Set keys in current record for (int i = 0; i < m_RecInfo.nKeys; i++) { JET_COLUMNID col_id; BOOL do_set = FALSE; ULONG size; WsbAffirmHr(pDbImp->GetJetIndexInfo(m_SessionId, m_RecInfo.Type, m_pKeyInfo[i].Type, &col_id, NULL, 0)); WsbAffirmHr(get_key(m_pKeyInfo[i].Type, temp_bytes1, &size)); if (m_SaveAsNew) { do_set = TRUE; } else { HRESULT hrEqual; hrEqual = jet_compare_field(col_id, temp_bytes1, size); WsbAffirm(S_OK == hrEqual || S_FALSE == hrEqual, hrEqual); if (S_FALSE == hrEqual && (m_pKeyInfo[i].Flags & IDB_KEY_FLAG_PRIMARY)) { // Changing the primary key is not allowed WsbThrow(WSB_E_IDB_PRIMARY_KEY_CHANGED); } do_set = (S_FALSE == hrEqual) ? TRUE : FALSE; } if (do_set) { WsbTrace(OLESTR("Setting key %ld\n"), m_pKeyInfo[i].Type); jstat = JetSetColumn(m_SessionId, m_TableId, col_id, temp_bytes1, size, 0, NULL); WsbAffirmHr(jet_error(jstat)); } } // Insert/update the record WsbTrace(OLESTR("Updating/writing record\n")); jstat = JetUpdate(m_SessionId, m_TableId, NULL, 0, NULL); WsbAffirmHr(jet_error(jstat)); CComQIPtr pDbSysPriv = m_pDbSys; WsbAffirmPointer(pDbSysPriv); WsbAffirmHr(pDbSysPriv->IncrementChangeCount()); m_SaveAsNew = FALSE; SetIsDirty(FALSE); } WsbCatch(hr); if (pDbImp) { WsbAffirmHr(pDbImp->Unlock()); } if (SUCCEEDED(hr)) { jstat = JetCommitTransaction(m_SessionId, 0); WsbTrace(OLESTR("CWsbDbEntity::Write: JetCommitTransaction = %ld\n"), jstat); } else { jstat = JetRollback(m_SessionId, 0); WsbTrace(OLESTR("CWsbDbEntity::Write: JetRollback = %ld\n"), jstat); } WsbTraceOut(OLESTR("CWsbDbEntity::Write"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDbEntity::FinalConstruct( void ) /*++ Implements: CComObjectRoot::FinalConstruct --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::FinalConstruct"), OLESTR("") ); try { WsbAffirmHr(CWsbObject::FinalConstruct()); m_pDb = NULL; m_SaveAsNew = FALSE; m_pKeyInfo = NULL; m_RecInfo.MaxSize = 0; m_SeqNum = -1; m_PosOk = FALSE; m_SessionId = 0; m_TableId = 0; m_hMem = 0; m_Sequential = FALSE; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::FinalConstruct"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } void CWsbDbEntity::FinalRelease( void ) /*++ Routine Description: This method does some cleanup of the object that is necessary during destruction. Arguments: None. Return Value: None. --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::FinalRelease"), OLESTR("")); WsbTrace(OLESTR("DbEntity SessionId = %lx, TableId = %ld\n"), m_SessionId, m_TableId); try { if (m_hMem) { GlobalFree(m_hMem); } if (m_SessionId && m_TableId) { if (m_Sequential) { (void)ResetSequentialScan(); } m_SessionId = 0; m_TableId = 0; } if (m_pDb) { // Release IDB objects m_pDb = 0; m_pDbSys = 0; } if (m_pKeyInfo) { WsbFree(m_pKeyInfo); m_pKeyInfo = NULL; } CWsbObject::FinalRelease(); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::FinalRelease"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); } HRESULT CWsbDbEntity::CompareTo( IN IUnknown* pCollectable, OUT SHORT* pResult ) /*++ Implements: IWsbCollectable::CompareTo --*/ { HRESULT hr = S_FALSE; IWsbDbEntity* pEntity; WsbTraceIn(OLESTR("CWsbDbEntity::CompareTo"), OLESTR("")); try { // Did they give us a valid item to compare to? WsbAssert(0 != pCollectable, E_POINTER); // We need the IWsbDbEntity interface to get the value of the object. WsbAffirmHr(pCollectable->QueryInterface(IID_IWsbDbEntity, (void**) &pEntity)); hr = compare(pEntity, pResult); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::CompareTo"), OLESTR("hr = <%ls>, result = <%ls>"), WsbHrAsString(hr), WsbPtrToShortAsString(pResult)); return(hr); } // CWsbDbEntity internal helper functions // compare - compare control key to control key of another entity HRESULT CWsbDbEntity::compare(IWsbDbEntity* pEntity, SHORT* pResult) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::compare"), OLESTR("")); try { CComPtr pCollectable; CComPtr pEntityPriv; CComPtr pKey1; CComPtr pKey2; SHORT result; WsbAffirmHr(GetCurKey(&pKey1)); WsbAffirmHr(pKey1->QueryInterface(IID_IWsbCollectable, (void**)&pCollectable)); WsbAffirmHr(pEntity->QueryInterface(IID_IWsbDbEntityPriv, (void**)&pEntityPriv)) WsbAffirmHr(pEntityPriv->GetCurKey(&pKey2)); WsbAffirmHr(pCollectable->CompareTo(pKey2, &result)); if (pResult) { *pResult = result; } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::compare"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // fromMem - load entity data from memory HRESULT CWsbDbEntity::fromMem(HGLOBAL hMem) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::fromMem"), OLESTR("")); try { CComPtr pIPersistStream; CComPtr pIStream; IUnknown* pIUnknown; WsbAssert(0 != hMem, E_POINTER); // Get PersistStream interfaces for myself pIUnknown = (IUnknown *)(IWsbPersistable *)(CWsbCollectable *)this; WsbAffirmHr(pIUnknown->QueryInterface(IID_IPersistStream, (void**) &pIPersistStream)); // Create a memory stream WsbAffirmHr(CreateStreamOnHGlobal(hMem, FALSE, &pIStream)); // Load myself from the stream WsbAffirmHr(pIPersistStream->Load(pIStream)); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::fromMem"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // get_key - get the byte array & size for the given key HRESULT CWsbDbEntity::get_key(ULONG key_type, UCHAR* bytes, ULONG* pSize) { HRESULT hr = S_OK; try { ULONG expected_size; ULONG size; if (0 != key_type) { UCHAR* pbytes; CComPtr pKey; CComPtr pKeyPriv; // Check that this is a valid key type for (int i = 0; i < m_RecInfo.nKeys; i++) { if (m_pKeyInfo[i].Type == key_type) break; } WsbAssert(i < m_RecInfo.nKeys, E_INVALIDARG); WsbAssert(0 != bytes, E_POINTER); // Create a key of the right type WsbAffirmHr(CoCreateInstance(CLSID_CWsbDbKey, 0, CLSCTX_SERVER, IID_IWsbDbKey, (void **)&pKey )); WsbAffirmHr(pKey->QueryInterface(IID_IWsbDbKeyPriv, (void**)&pKeyPriv)); WsbAffirmHr(pKeyPriv->SetType(key_type)); // Get the key's value from the derived code WsbAffirmHr(UpdateKey(pKey)); // Convert key to bytes pbytes = bytes; WsbAffirmHr(pKeyPriv->GetBytes(&pbytes, &size)); expected_size = m_pKeyInfo[i].Size; WsbAffirm(size <= expected_size, WSB_E_INVALID_DATA); while (size < expected_size) { // Fill with zeros pbytes[size] = '\0'; size++; } // 0 == key_type // This is a special case, allowed only for Jet, to // get the sequence number as a key. We can't use // WsbConvertToBytes because the bytes end up in the // wrong order. } else { size = sizeof(m_SeqNum); memcpy(bytes, (void*)&m_SeqNum, size); } if (pSize) { *pSize = size; } } WsbCatch(hr); return(hr); } // getMem - allocate enough memory for this entity HRESULT CWsbDbEntity::getMem(HGLOBAL* phMem) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::getMem"), OLESTR("")); try { HGLOBAL hMem; WsbAssert(0 != phMem, E_POINTER); WsbAffirm(0 < m_RecInfo.MaxSize, WSB_E_NOT_INITIALIZED); hMem = GlobalAlloc(GHND, m_RecInfo.MaxSize); WsbAffirm(hMem, E_OUTOFMEMORY); *phMem = hMem; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::getMem"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // toMem - save this entity to memory HRESULT CWsbDbEntity::toMem(HGLOBAL hMem, ULONG* pSize) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::toMem"), OLESTR("")); try { CComPtr pIPersistStream; CComPtr pIStream; IUnknown* pIUnknown; ULARGE_INTEGER seek_pos; LARGE_INTEGER seek_pos_in; WsbAssert(0 != hMem, E_POINTER); WsbAssert(0 != pSize, E_POINTER); // Get PersistStream interfaces for myself pIUnknown = (IUnknown *)(IWsbPersistable *)(CWsbCollectable *)this; WsbAffirmHr(pIUnknown->QueryInterface(IID_IPersistStream, (void**) &pIPersistStream)); // Create a memory stream WsbAffirmHr(CreateStreamOnHGlobal(hMem, FALSE, &pIStream)); // Save to the stream WsbAffirmHr(pIPersistStream->Save(pIStream, FALSE)); // Get the size seek_pos_in.QuadPart = 0; WsbAffirmHr(pIStream->Seek(seek_pos_in, STREAM_SEEK_CUR, &seek_pos)); *pSize = seek_pos.LowPart; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::toMem"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // jet_compare_field - compare a string of bytes to the a column // value in the current Jet record // Return S_OK for equal, S_FALSE for not equal, other for an error. HRESULT CWsbDbEntity::jet_compare_field(ULONG col_id, UCHAR* bytes, ULONG size) { VOID* addr = NULL; HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::jet_compare_field"), OLESTR("")); try { ULONG actualSize; JET_ERR jstat; CComPtr pDbImp; // Get some Jet DB info WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); // Get the column value addr = GlobalLock(m_hMem); WsbAffirm(addr, E_HANDLE); jstat = JetRetrieveColumn(m_SessionId, m_TableId, col_id, addr, size, &actualSize, 0, NULL); WsbAffirmHr(jet_error(jstat)); // Compare them if (memcmp(bytes, addr, size)) { hr = S_FALSE; } } WsbCatch(hr); if (NULL != addr) { GlobalUnlock(m_hMem); } WsbTraceOut(OLESTR("CWsbDbEntity::jet_compare_field"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // jet_get_data - retrieve record data from the current Jet record HRESULT CWsbDbEntity::jet_get_data(void) { VOID* addr = NULL; HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::jet_get_data"), OLESTR("")); try { ULONG actualSize; JET_COLUMNID col_id; JET_ERR jstat; CComPtr pDbImp; // Get some Jet DB info WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); // Get data addr = GlobalLock(m_hMem); WsbAffirm(addr, E_HANDLE); jstat = JetRetrieveColumn(m_SessionId, m_TableId, m_ColId, addr, m_RecInfo.MaxSize, &actualSize, 0, NULL); WsbAffirmHr(jet_error(jstat)); WsbAffirmHr(fromMem(m_hMem)); // Get the sequence number WsbAffirmHr(pDbImp->GetJetIndexInfo(m_SessionId, m_RecInfo.Type, 0, &col_id, NULL, 0)); jstat = JetRetrieveColumn(m_SessionId, m_TableId, col_id, &m_SeqNum, sizeof(m_SeqNum), &actualSize, 0, NULL); WsbAffirmHr(jet_error(jstat)); } WsbCatch(hr); if (NULL != addr) { GlobalUnlock(m_hMem); } WsbTraceOut(OLESTR("CWsbDbEntity::jet_get_data"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // jet_make_current - make sure this is the current Jet record // NOTE: This function, despite its name, does not attempt to force // the JET "cursor" to be on the correct record because this can mess // up too many things that can't necessarily be controlled at this // level. For one thing, if the current key allows duplicates, we can't // be sure to get to the correct record using the index for that key. // If we try to use the sequence number as the key, we'd then be using // the wrong index if we do a Next or Previous. If the user code is // doing a Write or Remove, it's better for that code to make sure via // the Find functions that the cursor is position correctly. HRESULT CWsbDbEntity::jet_make_current(void) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::jet_make_current"), OLESTR("")); try { ULONG actualSize; JET_COLUMNID col_id; JET_ERR jstat; CComPtr pDbImp; LONG seq_num; // Get some Jet DB info WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); WsbAffirmHr(pDbImp->GetJetIndexInfo(m_SessionId, m_RecInfo.Type, 0, &col_id, NULL, 0)); // Make sure this record is still the current record. // We do this by comparing the sequence numbers jstat = JetRetrieveColumn(m_SessionId, m_TableId, col_id, &seq_num, sizeof(seq_num), &actualSize, 0, NULL); WsbAffirmHr(jet_error(jstat)); if (!m_PosOk || seq_num != m_SeqNum) { WsbThrow(WSB_E_IDB_IMP_ERROR); } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::jet_make_current"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // jet_move - move current Jet record HRESULT CWsbDbEntity::jet_move(LONG pos) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::jet_move"), OLESTR("")); try { JET_ERR jstat; CComPtr pDbImp; // Get some Jet DB info WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); // Do the move jstat = JetMove(m_SessionId, m_TableId, pos, 0); if (jstat == JET_errNoCurrentRecord) { WsbThrow(WSB_E_NOTFOUND); } WsbAffirmHr(jet_error(jstat)); m_PosOk = TRUE; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::jet_move"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // jet_seek - find Jet record based on current key and seek_flag; // sets the current Jet record on success HRESULT CWsbDbEntity::jet_seek(ULONG seek_flag) { UCHAR temp_bytes1[IDB_MAX_KEY_SIZE + 4]; HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDbEntity::jet_seek"), OLESTR("")); try { JET_ERR jstat; CComPtr pDbImp; ULONG size; // Get some Jet DB info WsbAffirm(m_pDb, WSB_E_NOT_INITIALIZED); WsbAffirmHr(m_pDb->QueryInterface(IID_IWsbDbPriv, (void**)&pDbImp)); // Get the current key & give it to Jet WsbAffirmHr(get_key(m_pKeyInfo[m_UseKeyIndex].Type, temp_bytes1, &size)); jstat = JetMakeKey(m_SessionId, m_TableId, temp_bytes1, size, JET_bitNewKey); WsbAffirmHr(jet_error(jstat)); // Do the seek jstat = JetSeek(m_SessionId, m_TableId, seek_flag); if (jstat == JET_errRecordNotFound) { WsbThrow(WSB_E_NOTFOUND); } else if (jstat == JET_wrnSeekNotEqual) { jstat = JET_errSuccess; } WsbAffirmHr(jet_error(jstat)); m_PosOk = TRUE; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDbEntity::jet_seek"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); }