/*++ © 1998 Seagate Software, Inc. All rights reserved. Module Name: Wsbdb.cpp Abstract: These classes provide support for data bases. Author: Ron White [ronw] 19-Nov-1996 Revision History: --*/ #include "stdafx.h" #include "wsbdbsys.h" #include "wsbdbses.h" #include "wsbdbkey.h" #include #define JET_DATA_COLUMN_NAME "Data" #define JET_INDEX_COLUMN_NAME "Index" #define JET_INFO_TABLE_NAME "Info" #define JET_SEQNUM_COLUMN_NAME "SeqNum" #define SESSION_INFO_INITIAL_SIZE 4 #define SESSION_INFO_EXPANSION 6 #define JET_CURRENT_SESSION (pDbInfo->SessionInfo[m_SessionIndex].SessionId) #define JET_CURRENT_DB (pDbInfo->SessionInfo[m_SessionIndex].DbId) #define CATCH_ANY_EXCEPTION catch (...) { \ WsbTraceAndLogEvent(WSB_MESSAGE_IDB_EXCEPTION, 0, NULL, NULL); \ WsbTrace(OLESTR("GetLastError = %ld\n"), GetLastError()); \ hr = WSB_E_IDB_EXCEPTION; } // Local stuff // These structures hold extra implementation data typedef struct { } IMP_KEY_INFO; typedef struct { IMP_KEY_INFO* Key; } IMP_REC_INFO; // IMP_TABLE_INFO holds information for each open table typedef struct { JET_TABLEID TableId; JET_COLUMNID ColId; } IMP_TABLE_INFO; // IMP_SESSION_INFO holds information for each thread typedef struct { JET_SESID SessionId; // The Jet session JET_DBID DbId; // The session's DB ID for this DB IMP_TABLE_INFO* pTableInfo; // Array of table information } IMP_SESSION_INFO; typedef struct { BOOL IsLoaded; // DB info is loaded into memory USHORT OpenCount; // Open ref. count IMP_REC_INFO* RecInfo; // Array of record info SHORT nSessions; IMP_SESSION_INFO* SessionInfo; } IMP_DB_INFO; // These structures are saved in the data file typedef struct { ULONG Type; // Key type ID ULONG Size; // Key size in bytes ULONG Flags; // IDB_KEY_FLAG_* flags } FILE_KEY_INFO; typedef struct { ULONG Type; // Record type ID CLSID EntityClassId; // Derived entity class ID ULONG Flags; // IDB_REC_FLAG_* flags ULONG MinSize; // (Minimum) record size in bytes ULONG MaxSize; // Maximum record size USHORT nKeys; // Number of keys in this record type FILE_KEY_INFO Key[IDB_MAX_KEYS_PER_REC]; } FILE_REC_INFO; typedef struct { USHORT nRecTypes; // Number of record types ULONG version; // DB version } FILE_DB_INFO; //*************************************************************** // Local function prototypes static HRESULT jet_get_column_id(JET_SESID jet_session, JET_DBID DbId, char* pTableName, char* pColumnName, JET_COLUMNID* pColId); //*************************************************************** // Function definitions HRESULT CWsbDb::Create( IN OLECHAR* path, ULONG flags ) /*++ Implements: IWsbDb::Create --*/ { HRESULT hr = S_OK; IMP_DB_INFO* pDbInfo = NULL; WsbTraceIn(OLESTR("CWsbDb::Create"), OLESTR("path = <%ls>"), path); try { int key_index; ULONG memSize; int rec_index; WsbAssert(0 != path, E_POINTER); WsbAssert(0 != m_RecInfo, WSB_E_NOT_INITIALIZED); WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; Lock(); WsbAffirm(!pDbInfo->IsLoaded, WSB_E_NOT_INITIALIZED); WsbAffirm(!pDbInfo->RecInfo, WSB_E_NOT_INITIALIZED); // Save the path m_path = path; // Check validity of some info that the derived class is // suppose to supply. WsbAffirm(m_version != 0, WSB_E_NOT_INITIALIZED); WsbAffirm(m_nRecTypes > 0, WSB_E_NOT_INITIALIZED); WsbAffirm(m_nRecTypes <= IDB_MAX_REC_TYPES, WSB_E_INVALID_DATA); pDbInfo->IsLoaded = TRUE; // Allocate the RecInfo array memSize = m_nRecTypes * sizeof(IMP_REC_INFO); pDbInfo->RecInfo = (IMP_REC_INFO*)WsbAlloc(memSize); WsbAffirm(pDbInfo->RecInfo, E_OUTOFMEMORY); ZeroMemory(pDbInfo->RecInfo, memSize); char index_names[IDB_MAX_KEYS_PER_REC + 1][20]; JET_COLUMNCREATE jet_columns[IDB_MAX_KEYS_PER_REC + 2]; JET_INDEXCREATE jet_indices[IDB_MAX_KEYS_PER_REC + 1]; JET_TABLECREATE jet_table; JET_ERR jstat; char key_names[IDB_MAX_KEYS_PER_REC + 1][22]; char* name; char table_name[20]; JET_GRBIT createFlags = 0; // Start a Jet session for this thread WsbAffirmHr(jet_init()); // Make sure there's room for another DB CComQIPtr pDbSysPriv = m_pWsbDbSys; WsbAffirmPointer(pDbSysPriv); WsbAffirmHr(pDbSysPriv->DbAttachedAdd(path, FALSE)); // Set creation flag if (flags & IDB_CREATE_FLAG_NO_TRANSACTION) { // Setting this flag stil allow transaction calls - they are just being ignored and MT-safe is not guaranteed createFlags |= (JET_bitDbVersioningOff & JET_bitDbRecoveryOff); } // Create the DB WsbAffirmHr(wsb_db_jet_fix_path(path, L"." IDB_DB_FILE_SUFFIX, &name)); jstat = JetCreateDatabase(JET_CURRENT_SESSION, name, NULL, &JET_CURRENT_DB, createFlags); WsbTrace(OLESTR("JetCreateDB = %ld\n"), (LONG)jstat); WsbFree(name); WsbAffirmHr(jet_error(jstat)); // Set up constant part of table structure jet_table.cbStruct = sizeof(JET_TABLECREATE); jet_table.szTemplateTableName = NULL; jet_table.ulPages = 4; // ???? jet_table.ulDensity = 50; // ????? jet_table.rgcolumncreate = jet_columns; jet_table.rgindexcreate = jet_indices; jet_table.grbit = 0; // Set up the constant part of the column structures ZeroMemory(&jet_columns, sizeof(jet_columns)); ZeroMemory(&jet_indices, sizeof(jet_indices)); jet_columns[0].cbStruct = sizeof(JET_COLUMNCREATE); jet_columns[0].szColumnName = JET_DATA_COLUMN_NAME; jet_columns[1].cbStruct = sizeof(JET_COLUMNCREATE); // Create a "table" to hold info about this DB jet_table.szTableName = JET_INFO_TABLE_NAME; jet_table.cColumns = 2; jet_table.cIndexes = 1; jet_columns[0].coltyp = JET_coltypLongBinary; jet_columns[0].cbMax = sizeof(FILE_REC_INFO); jet_columns[1].szColumnName = JET_INDEX_COLUMN_NAME; jet_columns[1].coltyp = JET_coltypShort; jet_columns[1].cbMax = sizeof(SHORT); jet_indices[0].cbStruct = sizeof(JET_INDEXCREATE); jet_indices[0].szIndexName = JET_INDEX_COLUMN_NAME; ZeroMemory(key_names[0], 22); sprintf(key_names[0], "+%s", JET_INDEX_COLUMN_NAME); jet_indices[0].szKey = key_names[0]; jet_indices[0].cbKey = strlen(key_names[0]) + 2; jet_indices[0].grbit |= JET_bitIndexPrimary; jet_indices[0].ulDensity = 90; jstat = JetCreateTableColumnIndex(JET_CURRENT_SESSION, JET_CURRENT_DB, &jet_table); WsbTrace(OLESTR("CWsbDb::Create: JetCreateTableColumnIndex status = %ld\n"), jstat); if (JET_errSuccess != jstat) { WsbTrace(OLESTR("CWsbDb::Create: JetCreateTableColumnIndex, cCreated = %ld\n"), jet_table.cCreated); } WsbAffirmHr(jet_error(jstat)); jstat = JetCloseTable(JET_CURRENT_SESSION, jet_table.tableid); WsbTrace(OLESTR("CWsbDb::Create: close TableId = %ld, jstat = %ld\n"), jet_table.tableid, jstat); // Write DB info jstat = JetBeginTransaction(JET_CURRENT_SESSION); WsbTrace(OLESTR("CWsbDb::Create: JetBeginTransaction = %ld\n"), jstat); jstat = jet_save_info(); if (JET_errSuccess == jstat) { jstat = JetCommitTransaction(JET_CURRENT_SESSION, 0); WsbTrace(OLESTR("CWsbDb::Create: JetCommitTransaction = %ld\n"), jstat); } else { HRESULT hr2 = jet_error(jstat); jstat = JetRollback(JET_CURRENT_SESSION, 0); WsbTrace(OLESTR("CWsbDb::Create: JetRollback = %ld\n"), jstat); WsbThrow(hr2); } // We create a table for each record type. The first column of each // table is the record (stored as a blob). The second column is a // unique sequence number for each record. The rest of the columns are for // key values used as indices. jet_columns[1].szColumnName = JET_SEQNUM_COLUMN_NAME; jet_columns[1].coltyp = JET_coltypLong; jet_columns[1].cbMax = sizeof(ULONG); jet_columns[1].grbit = JET_bitColumnAutoincrement; jet_indices[0].cbStruct = sizeof(JET_INDEXCREATE); strcpy(index_names[0], JET_SEQNUM_COLUMN_NAME); jet_indices[0].szIndexName = index_names[0]; ZeroMemory(key_names[0], 22); sprintf(key_names[0], "+%s", index_names[0]); jet_indices[0].szKey = key_names[0]; jet_indices[0].cbKey = strlen(key_names[0]) + 2; jet_indices[0].grbit = 0; jet_indices[0].ulDensity = 90; // Loop over record types for (rec_index = 0; rec_index < m_nRecTypes; rec_index++) { WsbAffirm(m_RecInfo[rec_index].Type > 0, WSB_E_NOT_INITIALIZED); WsbAffirm(m_RecInfo[rec_index].nKeys > 0, WSB_E_NOT_INITIALIZED); WsbAffirm(m_RecInfo[rec_index].nKeys <= IDB_MAX_KEYS_PER_REC, WSB_E_INVALID_DATA); // Allocate the Key array memSize = m_RecInfo[rec_index].nKeys * sizeof(IMP_KEY_INFO); pDbInfo->RecInfo[rec_index].Key = (IMP_KEY_INFO*)WsbAlloc(memSize); WsbAffirm(pDbInfo->RecInfo[rec_index].Key, E_OUTOFMEMORY); ZeroMemory(pDbInfo->RecInfo[rec_index].Key, memSize); // Fill in the table structure with info specific to this // record type WsbAffirmHr(jet_make_table_name(m_RecInfo[rec_index].Type, table_name, 20)); jet_table.szTableName = table_name; jet_table.cColumns = m_RecInfo[rec_index].nKeys + 2; jet_table.cIndexes = m_RecInfo[rec_index].nKeys + 1; // Fill in the column structure for the record itself if (m_RecInfo[rec_index].MaxSize < 255) { jet_columns[0].coltyp = JET_coltypBinary; } else { jet_columns[0].coltyp = JET_coltypLongBinary; } jet_columns[0].cbMax = m_RecInfo[rec_index].MaxSize; // Loop over keys for (key_index = 0; key_index < m_RecInfo[rec_index].nKeys; key_index++) { WsbAffirm(m_RecInfo[rec_index].Key[key_index].Type > 0, WSB_E_NOT_INITIALIZED); WsbAffirm(m_RecInfo[rec_index].Key[key_index].Size <= IDB_MAX_KEY_SIZE, WSB_E_NOT_INITIALIZED); WsbAffirm(!(m_RecInfo[rec_index].Key[key_index].Flags & IDB_KEY_FLAG_PRIMARY) || !(m_RecInfo[rec_index].Key[key_index].Flags & IDB_KEY_FLAG_DUP_ALLOWED), WSB_E_IDB_PRIMARY_UNIQUE); // Fill in a column structure for each key jet_columns[key_index + 2].cbStruct = sizeof(JET_COLUMNCREATE); WsbAffirmHr(jet_make_index_name(m_RecInfo[rec_index].Key[key_index].Type, index_names[key_index + 1], 20)); jet_columns[key_index + 2].szColumnName = index_names[key_index + 1]; jet_columns[key_index + 2].grbit = JET_bitColumnFixed; jet_columns[key_index + 2].pvDefault = NULL; jet_columns[key_index + 2].cbDefault = 0; if (m_RecInfo[rec_index].Key[key_index].Size < 255) { jet_columns[key_index + 2].coltyp = JET_coltypBinary; } else { jet_columns[key_index + 2].coltyp = JET_coltypLongBinary; } jet_columns[key_index + 2].cbMax = m_RecInfo[rec_index].Key[key_index].Size; // Fill in an index structure for each key jet_indices[key_index + 1].cbStruct = sizeof(JET_INDEXCREATE); jet_indices[key_index + 1].szIndexName = index_names[key_index + 1]; ZeroMemory(key_names[key_index + 1], 22); sprintf(key_names[key_index + 1], "+%s\0", index_names[key_index + 1]); jet_indices[key_index + 1].szKey = key_names[key_index + 1]; jet_indices[key_index + 1].cbKey = strlen(key_names[key_index + 1]) + 2; if (m_RecInfo[rec_index].Key[key_index].Flags & IDB_KEY_FLAG_DUP_ALLOWED) { jet_indices[key_index + 1].grbit = 0; } else { jet_indices[key_index + 1].grbit = JET_bitIndexUnique; } if (m_RecInfo[rec_index].Key[key_index].Flags & IDB_KEY_FLAG_PRIMARY) { jet_indices[key_index + 1].grbit |= JET_bitIndexPrimary; } jet_indices[key_index + 1].ulDensity = 50; } // End of key loop // Set table creation flags if (flags & IDB_CREATE_FLAG_FIXED_SCHEMA) { jet_table.grbit |= JET_bitTableCreateFixedDDL; } // Create the "table" for each record type; this call defines // the columns (fields) and index keys jstat = JetCreateTableColumnIndex(JET_CURRENT_SESSION, JET_CURRENT_DB, &jet_table); WsbTrace(OLESTR("JetCreateTableColumnIndex = %ld\n"), jstat); WsbAffirmHr(jet_error(jstat)); jstat = JetCloseTable(JET_CURRENT_SESSION, jet_table.tableid); WsbTrace(OLESTR("CWsbDb::Create: close TableId = %ld, jstat = %ld\n"), jet_table.tableid, jstat); } // End of record loop jstat = JetCloseDatabase(JET_CURRENT_SESSION, JET_CURRENT_DB, 0); WsbTrace(OLESTR("CWsbDb::Create: JetCloseDatabase = %ld\n"), (LONG)jstat); JET_CURRENT_DB = 0; pDbInfo->OpenCount = 0; } WsbCatchAndDo(hr, WsbLogEvent(WSB_MESSAGE_IDB_CREATE_FAILED, 0, NULL, WsbAbbreviatePath(path, 120), NULL); ) CATCH_ANY_EXCEPTION if (pDbInfo) { Unlock(); } WsbTraceOut(OLESTR("CWsbDb::Create"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::Delete( IN OLECHAR *path, ULONG flags ) /*++ Implements: IWsbDb::Delete --*/ { HRESULT hr = S_OK; char* name = NULL; IMP_DB_INFO* pDbInfo = NULL; WsbTraceIn(OLESTR("CWsbDb::Delete"), OLESTR("path = <%ls>"), WsbStringAsString(path)); try { CWsbStringPtr DeletePath; WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; Lock(); // Can't delete it if it's open WsbAffirm(pDbInfo->OpenCount == 0, E_UNEXPECTED); if (NULL == path) { path = m_path; } WsbAffirm(path && wcslen(path), S_FALSE); WsbAffirmHr(wsb_db_jet_fix_path(path, L"." IDB_DB_FILE_SUFFIX, &name)); // Detach (if attached) CComQIPtr pDbSysPriv = m_pWsbDbSys; WsbAffirmPointer(pDbSysPriv); WsbAffirmHr(pDbSysPriv->DbAttachedRemove(path)); // Now delete it DeletePath = name; if (!DeleteFile(DeletePath)) { DWORD err = GetLastError(); WsbTrace(OLESTR("CWsbDb::Delete: DeleteFile(%ls) failed, error = %ld\n"), static_cast(DeletePath), err); WsbThrow(HRESULT_FROM_WIN32(err)); } // Put message in event log if (flags & IDB_DELETE_FLAG_NO_ERROR) { WsbLogEvent(WSB_E_IDB_DATABASE_DELETED_NO_ERROR, 0, NULL, WsbAbbreviatePath(DeletePath, 120), NULL); } else { WsbLogEvent(WSB_E_IDB_DATABASE_DELETED, 0, NULL, WsbAbbreviatePath(DeletePath, 120), NULL); } } WsbCatch(hr) if (pDbInfo) { Unlock(); } if (name) { WsbFree(name); } WsbTraceOut(OLESTR("CWsbDb::Delete"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::Dump( IN OLECHAR* Filename, IN ULONG Flags, IN ULONG Data ) /*++ Implements: IWsbDb::Dump --*/ { HANDLE hFile = 0; HRESULT hr = S_OK; IMP_DB_INFO* pDbInfo = NULL; CComPtr pSession; WsbTraceIn(OLESTR("CWsbDb::Dump"), OLESTR("path = <%ls>"), Filename); try { DWORD CreateFlags; int i; int index; CComPtr pIRec; CComPtr pStream; WsbAssert(0 != Filename, E_POINTER); WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; Lock(); // WsbAffirmHr(session_current_index(Session)); // Open the Db // SteveW // added code to ensure that a database was opened // if not go on to the next database, but do not // throw an exception. // hr = Open(&pSession); if (hr == S_OK) { // Open/create the output file if (Flags & IDB_DUMP_FLAG_APPEND_TO_FILE) { CreateFlags = OPEN_ALWAYS; } else { CreateFlags = CREATE_ALWAYS; } hFile = CreateFile(Filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CreateFlags, FILE_ATTRIBUTE_NORMAL, NULL); WsbAffirmHandle(hFile); if (Flags & IDB_DUMP_FLAG_APPEND_TO_FILE) { // Position to the end of the file SetFilePointer(hFile, 0, NULL, FILE_END); } // Create the output stream WsbAffirmHr(CreateStreamOnHGlobal(NULL, TRUE, &pStream)); // Dump general DB info if (Flags & IDB_DUMP_FLAG_DB_INFO) { WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("Dump of DB: %ls\n"), static_cast(m_path))); WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR(" version = %ld, # record types = %d\n"), m_version, m_nRecTypes)); WsbAffirmHr(WsbStreamToFile(hFile, pStream, TRUE)); } // Loop over record types for (i = 0; i < m_nRecTypes; i++) { // Dump record info if (Flags & IDB_DUMP_FLAG_REC_INFO) { WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("RecType = %8ld, Flags = %0.8lx, "), m_RecInfo[i].Type, m_RecInfo[i].Flags)); WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("MaxSize = %8ld, # keys = %4d\n"), m_RecInfo[i].MaxSize, m_RecInfo[i].nKeys)); WsbAffirmHr(WsbStreamToFile(hFile, pStream, TRUE)); } // Dump key info if (Flags & IDB_DUMP_FLAG_KEY_INFO) { for (int j = 0; j < m_RecInfo[i].nKeys; j++) { WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR(" KeyType = %8ld, Size = %8ld, Flags = %0.8lx\n"), m_RecInfo[i].Key[j].Type, m_RecInfo[i].Key[j].Size, m_RecInfo[i].Key[j].Flags)); } WsbAffirmHr(WsbStreamToFile(hFile, pStream, TRUE)); } } // Dump records if (Flags & (IDB_DUMP_FLAG_RECORDS | IDB_DUMP_FLAG_RECORD_TYPE)) { for (i = 0; i < m_nRecTypes; i++) { if (!(Flags & IDB_DUMP_FLAG_RECORDS) && m_RecInfo[i].Type != Data) { continue; } WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("\n*** Dump of records of Type = %ld ***\n"), m_RecInfo[i].Type)); // Get a DB entity pIRec = 0; WsbAffirmHr(GetEntity(pSession, m_RecInfo[i].Type, IID_IWsbDbEntity, (void**)&pIRec)); // Loop over records index = 0; hr = pIRec->First(); while (S_OK == hr) { WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("%0.5d "), index)); WsbAffirmHr(pIRec->Print(pStream)); WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("\n"))); WsbAffirmHr(WsbStreamToFile(hFile, pStream, TRUE)); hr = pIRec->Next(); index++; } if (WSB_E_NOTFOUND == hr) { hr = S_OK; } else { WsbAffirmHr(hr); } } } } } WsbCatch(hr) CATCH_ANY_EXCEPTION if (hFile) { CloseHandle(hFile); } if (pSession) { Close(pSession); } if (pDbInfo) { Unlock(); } WsbTraceOut(OLESTR("CWsbDb::Dump"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::Locate( IN OLECHAR *path ) /*++ Implements: IWsbDb::Locate --*/ { HRESULT hr = S_OK; IMP_DB_INFO* pDbInfo = NULL; WsbTraceIn(OLESTR("CWsbDb::Locate"), OLESTR("path = <%ls>"), path); try { WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; Lock(); WsbAffirm(pDbInfo->OpenCount == 0, E_UNEXPECTED); m_path = path; JET_ERR jstat; char* name; // Start a Jet session for this thread WsbAffirmHr(jet_init()); WsbAffirmHr(wsb_db_jet_fix_path(path, L"." IDB_DB_FILE_SUFFIX, &name)); hr = S_OK; try { CComQIPtr pDbSysPriv = m_pWsbDbSys; WsbAffirmPointer(pDbSysPriv); WsbAffirmHr(pDbSysPriv->DbAttachedAdd(path, TRUE)); jstat = JetOpenDatabase(JET_CURRENT_SESSION, name, NULL, &JET_CURRENT_DB, 0); if (jstat == JET_errDatabaseNotFound) { WsbThrow(STG_E_FILENOTFOUND); } else { WsbAffirmHr(jet_error(jstat)); } } WsbCatch(hr); WsbFree(name); WsbAffirmHr(hr); // Load information about this DB hr = jet_load_info(); jstat = JetCloseDatabase(JET_CURRENT_SESSION, JET_CURRENT_DB, 0); WsbTrace(OLESTR("CWsbDb::Locate: JetCloseDatabase = %ld\n"), (LONG)jstat); JET_CURRENT_DB = 0; pDbInfo = (IMP_DB_INFO*)m_pImp; pDbInfo->OpenCount = 0; } WsbCatch(hr) CATCH_ANY_EXCEPTION if (pDbInfo) { Unlock(); } WsbTraceOut(OLESTR("CWsbDb::Locate"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::Open( OUT IWsbDbSession** ppSession ) /*++ Implements: IWsbDb::Open --*/ { HRESULT hr = S_OK; IMP_DB_INFO* pDbInfo = NULL; WsbTraceIn(OLESTR("CWsbDb::Open"), OLESTR("")); try { ULONG Size = 0; WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; Lock(); WsbAffirmHr(m_path.GetLen(&Size)); WsbAffirm(Size > 0, WSB_E_NOT_INITIALIZED); // Make sure we have a session WsbAffirm(0 != ppSession, E_POINTER); if (0 == *ppSession) { WsbAffirmHr(m_pWsbDbSys->NewSession(ppSession)); WsbTrace(OLESTR("CWsbDb::Open: session created\n")); } int i; JET_ERR jstat; ULONG memSize; char* name; JET_SESID SessionId; int s_index; IMP_SESSION_INFO* s_info = pDbInfo->SessionInfo; CComQIPtr pSessionPriv = *ppSession; WsbAffirm(0 < pDbInfo->nSessions, WSB_E_NOT_INITIALIZED); WsbAffirm(pSessionPriv, E_FAIL); // Get the JET session ID WsbAffirmHr(pSessionPriv->GetJetId(&SessionId)); // We need to save session info; look for an empty slot. WsbTrace(OLESTR("CWsbDb::Open: nSessions = %d, SessionId = %lx\n"), ( int)pDbInfo->nSessions, SessionId); s_index = pDbInfo->nSessions; for (i = 0; i < pDbInfo->nSessions; i++) { WsbTrace(OLESTR("CWsbDb::Open: s_info[%d] = %lx\n"), i, s_info[i].SessionId); // Check for a duplicate session ID already in the table if (SessionId == s_info[i].SessionId) { s_index = i; break; // Check for an unused slot } else if (0 == s_info[i].SessionId && 0 == s_info[i].DbId && s_index == pDbInfo->nSessions) { s_index = i; } } WsbTrace(OLESTR("CWsbDb::Open: s_index = %d\n"), s_index); if (s_index == pDbInfo->nSessions) { SHORT newNum; // Didn't find an empty slot; expand the array newNum = (SHORT) ( s_index + SESSION_INFO_EXPANSION ); WsbTrace(OLESTR("CWsbDb::Open: expanding session table from %d to %d\n"), s_index, newNum); memSize = newNum * sizeof(IMP_SESSION_INFO); s_info = (IMP_SESSION_INFO*)WsbRealloc(pDbInfo->SessionInfo, memSize); WsbAffirm(s_info, E_OUTOFMEMORY); ZeroMemory(&s_info[s_index], SESSION_INFO_EXPANSION * sizeof(IMP_SESSION_INFO)); pDbInfo->SessionInfo = s_info; pDbInfo->nSessions = newNum; } // Save the session ID and index m_SessionIndex = s_index; s_info[s_index].SessionId = SessionId; WsbTrace(OLESTR("CWsbDB::Open, s_info = %lx, SessionId[%d] = %lx\n"), (LONG)s_index, m_SessionIndex, JET_CURRENT_SESSION); WsbAffirmHr(wsb_db_jet_fix_path(m_path, L"." IDB_DB_FILE_SUFFIX, &name)); CComQIPtr pDbSysPriv = m_pWsbDbSys; WsbAffirmPointer(pDbSysPriv); WsbAffirmHr(pDbSysPriv->DbAttachedAdd(m_path, TRUE)); jstat = JetOpenDatabase(JET_CURRENT_SESSION, name, NULL, &JET_CURRENT_DB, 0); WsbFree(name); if (jstat == JET_errDatabaseNotFound) { WsbThrow(STG_E_FILENOTFOUND); } else { WsbAffirmHr(jet_error(jstat)); } // Allocate/zero the table info array memSize = m_nRecTypes * sizeof(IMP_TABLE_INFO); WsbTrace(OLESTR("CWsbDb::Open: pTableInfo = %lx\n"), s_info[m_SessionIndex].pTableInfo); if (NULL == s_info[m_SessionIndex].pTableInfo) { s_info[m_SessionIndex].pTableInfo = (IMP_TABLE_INFO*)WsbAlloc(memSize); WsbAffirm(s_info[m_SessionIndex].pTableInfo, E_OUTOFMEMORY); WsbTrace(OLESTR("CWsbDb::Open: new pTableInfo = %lx\n"), s_info[m_SessionIndex].pTableInfo); } ZeroMemory(s_info[m_SessionIndex].pTableInfo, memSize); pDbInfo->OpenCount++; } WsbCatchAndDo(hr, WsbLogEvent(WSB_MESSAGE_IDB_OPEN_FAILED, 0, NULL, WsbAbbreviatePath(m_path, 120), NULL); ) CATCH_ANY_EXCEPTION if (pDbInfo) { Unlock(); } WsbTraceOut(OLESTR("CWsbDb::Open"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::Close( IN IWsbDbSession* pSession ) /*++ Implements: IWsbDb::Close - The element was added. --*/ { HRESULT hr = S_OK; IMP_DB_INFO* pDbInfo = NULL; WsbTraceIn(OLESTR("CWsbDb::Close"), OLESTR("")); try { WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; Lock(); WsbAffirm(pDbInfo->OpenCount, WSB_E_NOT_INITIALIZED); WsbAffirmHr(session_current_index(pSession)); pDbInfo->OpenCount--; JET_ERR jstat; IMP_SESSION_INFO* s_info = pDbInfo->SessionInfo; WsbTrace(OLESTR("CWsbDb::Close: closing DB, SessionId = %lx, DbId = %lx\n"), (LONG)s_info[m_SessionIndex].SessionId, (LONG)s_info[m_SessionIndex].DbId); jstat = JetCloseDatabase(s_info[m_SessionIndex].SessionId, s_info[m_SessionIndex].DbId, 0); WsbTrace(OLESTR("CWsbDb::Close: JetCloseDatabase = %ld\n"), (LONG)jstat); if (s_info[m_SessionIndex].pTableInfo) { WsbTrace(OLESTR("CWsbDb::Close: releasing pTableInfo\n")); WsbFree(s_info[m_SessionIndex].pTableInfo); s_info[m_SessionIndex].pTableInfo = NULL; } s_info[m_SessionIndex].SessionId = 0; s_info[m_SessionIndex].DbId = 0; } WsbCatch(hr) CATCH_ANY_EXCEPTION if (pDbInfo) { Unlock(); } WsbTraceOut(OLESTR("CWsbDb::Close"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::GetEntity( IN IWsbDbSession* pSession, IN ULONG RecId, IN REFIID riid, OUT void** ppEntity ) /*++ Implements: IWsbDb::GetEntity --*/ { HRESULT hr = S_OK; IMP_DB_INFO* pDbInfo = NULL; CComPtr pEntity; WsbTraceIn(OLESTR("CWsbDb::GetEntity"), OLESTR("")); try { CComQIPtr pIWsbDb = (IWsbDbPriv*)this; int rec_index; WsbAssert(0 != ppEntity, E_POINTER); WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; Lock(); WsbAffirmHr(session_current_index(pSession)); // Find the record info for (rec_index = 0; rec_index < m_nRecTypes; rec_index++) { if (m_RecInfo[rec_index].Type == RecId) break; } WsbAffirm(rec_index < m_nRecTypes, E_INVALIDARG); // Create the instance, initialize it to point to this DB, and // return the pointer to the caller. WsbAffirmHr(CoCreateInstance(m_RecInfo[rec_index].EntityClassId, NULL, CLSCTX_SERVER | CLSCTX_INPROC_HANDLER, IID_IWsbDbEntityPriv, (void**) &pEntity)); WsbAffirmHr(pEntity->Init(pIWsbDb, m_pWsbDbSys, RecId, JET_CURRENT_SESSION)); WsbAffirmHr(pEntity->QueryInterface(riid, (void**)ppEntity)); } WsbCatch(hr) CATCH_ANY_EXCEPTION if (pDbInfo) { Unlock(); } WsbTraceOut(OLESTR("CWsbDb::GetEntity"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::GetKeyInfo( IN ULONG RecType, IN USHORT nKeys, OUT COM_IDB_KEY_INFO* pKeyInfo ) /*++ Implements: IWsbDbPriv::GetKeyInfo --*/ { HRESULT hr = E_FAIL; WsbTraceIn(OLESTR("CWsbDb::GetKeyInfo"), OLESTR("")); try { IMP_DB_INFO* pDbInfo; WsbAssert(0 < nKeys, E_INVALIDARG); WsbAssert(0 != pKeyInfo, E_POINTER); WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; for (int i = 0; i < m_nRecTypes; i++) { if (m_RecInfo[i].Type == RecType) { USHORT n = min(nKeys, m_RecInfo[i].nKeys); for (int j = 0; j < n; j++) { pKeyInfo[j].Type = m_RecInfo[i].Key[j].Type; pKeyInfo[j].Size = m_RecInfo[i].Key[j].Size; pKeyInfo[j].Flags = m_RecInfo[i].Key[j].Flags; } hr = S_OK; break; } } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::GetKeyInfo"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::GetRecInfo( IN ULONG RecType, OUT COM_IDB_REC_INFO* pRecInfo ) /*++ Implements: IWsbDbPriv::GetRecInfo --*/ { HRESULT hr = E_FAIL; WsbTraceIn(OLESTR("CWsbDb::GetRecInfo"), OLESTR("")); try { IMP_DB_INFO* pDbInfo; WsbAssert(0 != pRecInfo, E_POINTER); WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; for (int i = 0; i < m_nRecTypes; i++) { if (m_RecInfo[i].Type == RecType) { pRecInfo->Type = m_RecInfo[i].Type; pRecInfo->EntityClassId = m_RecInfo[i].EntityClassId; pRecInfo->Flags = m_RecInfo[i].Flags; pRecInfo->MinSize = m_RecInfo[i].MinSize; pRecInfo->MaxSize = m_RecInfo[i].MaxSize; pRecInfo->nKeys = m_RecInfo[i].nKeys; hr = S_OK; break; } } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::GetRecInfo"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // GetJetIds - for a given record type, return the session ID, // the table ID, and the data column ID HRESULT CWsbDb::GetJetIds(JET_SESID SessionId, ULONG RecType, JET_TABLEID* pTableId, ULONG* pDataColId) { HRESULT hr = WSB_E_INVALID_DATA; WsbTraceIn(OLESTR("CWsbDb::GetJetIds"), OLESTR("")); try { JET_DBID DbId = 0; IMP_DB_INFO* pDbInfo; WsbAssert(0 != pTableId || 0 != pDataColId, E_POINTER); WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; WsbTrace(OLESTR("CWsbDb::GetJetIds: this = %p, pDbInfo = %p\n"), this, pDbInfo); for (int index = 0; index < pDbInfo->nSessions; index++) { if (pDbInfo->SessionInfo[index].SessionId == SessionId) { DbId = pDbInfo->SessionInfo[index].DbId; break; } } WsbTrace(OLESTR("CWsbDb::GetJetIds: index = %d, DbId = %ld\n"), index, (LONG)DbId); WsbAffirm(index < pDbInfo->nSessions, E_FAIL); WsbAffirm(pDbInfo->SessionInfo[index].pTableInfo, WSB_E_NOT_INITIALIZED); for (int i = 0; i < m_nRecTypes; i++) { if (m_RecInfo[i].Type == RecType) { JET_ERR jstat; char table_name[20]; IMP_TABLE_INFO* t_info = pDbInfo->SessionInfo[index].pTableInfo; WsbAffirmHr(jet_make_table_name(m_RecInfo[i].Type, table_name, 20)); WsbTrace(OLESTR("CWsbDb::GetJetIds: t_info = %p, i = %d, table_name = <%hs>\n"), t_info, i, table_name); if (0 == t_info[i].TableId && 0 == t_info[i].ColId) { // Open the table for this record type WsbTrace(OLESTR("CWsbDb::GetJetIds: opening Jet table, SessionId = %lx, DbId = %ld, table_name = <%hs>, &TableId = %p\n"), (LONG)SessionId, (LONG)DbId, table_name, (&t_info[i].TableId)); jstat = JetOpenTable(SessionId, DbId, table_name, NULL, 0, 0, &t_info[i].TableId); WsbTrace(OLESTR("CWsbDb::GetJetIds: TableId = %ld\n"), t_info[i].TableId); WsbAffirmHr(jet_error(jstat)); // Get the column ID for the data column WsbAffirmHr(jet_get_column_id(SessionId, DbId, table_name, JET_DATA_COLUMN_NAME, &t_info[i].ColId)); } if (0 != pTableId) { *pTableId = t_info[i].TableId; } if (0 != pDataColId) { *pDataColId = t_info[i].ColId; } hr = S_OK; break; } } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::GetJetIds"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // GetJetIndexInfo - for a given record type and key type, return information // about the key/index: the key size (in bytes), the column ID, // the index name HRESULT CWsbDb::GetJetIndexInfo(JET_SESID SessionId, ULONG RecType, ULONG KeyType, ULONG* pColId, OLECHAR** pName, ULONG bufferSize) { HRESULT hr = WSB_E_INVALID_DATA; WsbTraceIn(OLESTR("CWsbDb::GetJetIndexInfo"), OLESTR("")); try { JET_DBID DbId = 0; IMP_DB_INFO* pDbInfo; WsbAssert(0 != pColId || 0 != pName, E_POINTER); WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; for (int index = 0; index < pDbInfo->nSessions; index++) { if (pDbInfo->SessionInfo[index].SessionId == SessionId) { DbId = pDbInfo->SessionInfo[index].DbId; break; } } WsbAffirm(index < pDbInfo->nSessions, E_FAIL); for (int i = 0; i < m_nRecTypes; i++) { if (m_RecInfo[i].Type == RecType) { char index_name[20]; char table_name[20]; WsbAffirmHr(jet_make_table_name(RecType, table_name, 20)); if (0 == KeyType) { if (0 != pName) { WsbAffirm(bufferSize > strlen(JET_SEQNUM_COLUMN_NAME), E_FAIL); WsbAffirm(0 < mbstowcs(*pName, JET_SEQNUM_COLUMN_NAME, strlen(JET_SEQNUM_COLUMN_NAME) + 1), E_FAIL); } if (0 != pColId) { WsbAffirmHr(jet_get_column_id(SessionId, DbId, table_name, JET_SEQNUM_COLUMN_NAME, pColId)); } hr = S_OK; } else { // Search for the given key type for (int j = 0; j < m_RecInfo[i].nKeys; j++) { if (m_RecInfo[i].Key[j].Type == KeyType) { WsbAffirmHr(jet_make_index_name(KeyType, index_name, 20)); if (0 != pName) { WsbAffirm(bufferSize > strlen(index_name), E_FAIL); WsbAffirm(0 < mbstowcs(*pName, index_name, strlen(index_name) + 1), E_FAIL); } if (0 != pColId) { WsbAffirmHr(jet_get_column_id(SessionId, DbId, table_name, index_name, pColId)); } hr = S_OK; break; } } } break; } } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::GetJetIndexInfo"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::FinalConstruct( void ) /*++ Implements: CComObjectRoot::FinalConstruct --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDb::FinalConstruct"), OLESTR("") ); try { IMP_DB_INFO* pDbInfo; WsbAffirmHr(CWsbPersistable::FinalConstruct()); m_nRecTypes = 0; m_version = 0; m_pImp = NULL; m_RecInfo = NULL; m_SessionIndex = 0; // Allocate space for DB info & set pDbInfo = (IMP_DB_INFO*)WsbAlloc(sizeof(IMP_DB_INFO)); m_pImp = pDbInfo; WsbAffirm(pDbInfo, E_OUTOFMEMORY); ZeroMemory(pDbInfo, sizeof(IMP_DB_INFO)); pDbInfo->IsLoaded = FALSE; pDbInfo->OpenCount = 0; pDbInfo->nSessions = 0; pDbInfo->SessionInfo = NULL; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::FinalConstruct"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } void CWsbDb::FinalRelease( void ) /*++ Implements: CComObjectRoot::FinalRelease --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDb::FinalRelease"), OLESTR("")); try { if (m_pImp) { int i; IMP_DB_INFO* pDbInfo; pDbInfo = (IMP_DB_INFO*)m_pImp; if (pDbInfo->RecInfo) { for (i = 0; i < m_nRecTypes; i++) { if (pDbInfo->RecInfo[i].Key) { WsbFree(pDbInfo->RecInfo[i].Key); } } WsbFree(pDbInfo->RecInfo); } // Make sure Jet resources are released if (NULL != pDbInfo->SessionInfo) { IMP_SESSION_INFO* s_info = pDbInfo->SessionInfo; for (i = 0; i < pDbInfo->nSessions; i++) { if (0 != s_info[i].SessionId && 0 != s_info[i].DbId) { JET_ERR jstat; jstat = JetCloseDatabase(s_info[i].SessionId, s_info[i].DbId, 0); WsbTrace(OLESTR("CWsbDb::FinalRelease: JetCloseDatabase[%d] = %ld\n"), i, (LONG)jstat); } if (s_info[i].pTableInfo) { WsbFree(s_info[i].pTableInfo); s_info[i].pTableInfo = NULL; } s_info[i].SessionId = 0; s_info[i].DbId = 0; } WsbFree(pDbInfo->SessionInfo); pDbInfo->SessionInfo = NULL; } pDbInfo->nSessions = 0; WsbFree(pDbInfo); m_pImp = NULL; } if (m_RecInfo) { for (int i = 0; i < m_nRecTypes; i++) { if (m_RecInfo[i].Key) { WsbFree(m_RecInfo[i].Key); } } WsbFree(m_RecInfo); m_RecInfo = NULL; } CWsbPersistable::FinalRelease(); } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::FinalRelease"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); } HRESULT CWsbDb::GetClassID( OUT CLSID* pClsid ) /*++ Implements: IPersist::GetClassID(). --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDb::GetClassID"), OLESTR("")); try { WsbAssert(0 != pClsid, E_POINTER); *pClsid = CLSID_CWsbDb; } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid)); return(hr); } HRESULT CWsbDb::Load( IN IStream* pStream ) /*++ Implements: IPersistStream::Load(). --*/ { HRESULT hr = S_OK; OLECHAR* name = NULL; WsbTraceIn(OLESTR("CWsbDb::Load"), OLESTR("")); try { ULONG Bytes; ULONG len = 0; IMP_DB_INFO* pDbInfo; FILE_DB_INFO db_file_block; // Used to move info to/from file CComQIPtr pIWsbDb = (IWsbDbPriv*)this; WsbAssert(0 != pStream, E_POINTER); WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; // Don't allow loading into an already open DB WsbAffirm(pDbInfo->OpenCount == 0, WSB_E_INVALID_DATA); // Read the DB file name WsbAffirmHr(WsbLoadFromStream(pStream, &name, 0)); if (name) { len = wcslen(name); } // If the DB name is empty, there is no more info if (0 < len) { // Alloc space and read DB info WsbAffirmHr(pStream->Read((void*)&db_file_block, sizeof(FILE_DB_INFO), &Bytes)); WsbAffirm(Bytes == sizeof(FILE_DB_INFO), WSB_E_STREAM_ERROR); // Check DB version for match WsbAffirm(db_file_block.version == m_version, WSB_E_IDB_WRONG_VERSION); // Locate the DB WsbAffirmHr(db_info_from_file_block(&db_file_block)); hr = Locate(name); if (S_OK != hr) { if (pDbInfo->RecInfo) { WsbFree(pDbInfo->RecInfo); pDbInfo->RecInfo = NULL; } } } else { hr = S_FALSE; } } WsbCatch(hr); WsbFree(name); WsbTraceOut(OLESTR("CWsbDb::Load"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } HRESULT CWsbDb::Save( IN IStream* pStream, IN BOOL clearDirty ) /*++ Implements: IPersistStream::Save(). --*/ { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDb::Save"), OLESTR("")); try { ULONG Bytes; ULONG len = 0; FILE_DB_INFO db_file_block; // Used to move info to/from file WsbAssert(0 != pStream, E_POINTER); WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED); // Save the DB name WsbAffirmHr(WsbSaveToStream(pStream, m_path)); WsbAffirmHr(m_path.GetLen(&len)); // If the name is empty, none of the other information is likely // to be useful if (0 < len) { // Write some DB info WsbAffirm(m_nRecTypes, WSB_E_NOT_INITIALIZED); WsbAffirmHr(db_info_to_file_block(&db_file_block)); WsbAffirmHr(pStream->Write((void*)&db_file_block, sizeof(FILE_DB_INFO), &Bytes)); WsbAffirm(Bytes == sizeof(FILE_DB_INFO), WSB_E_STREAM_ERROR); } if (clearDirty) { SetIsDirty(FALSE); } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::Save"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // // Private functions // // db_info_from_file_block - copy data from DB info file block HRESULT CWsbDb::db_info_from_file_block(void* block) { HRESULT hr = S_OK; try { IMP_DB_INFO* pDbInfo; ULONG Size; FILE_DB_INFO *pDbFileBlock = (FILE_DB_INFO*)block; WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; WsbAssert(0 != pDbFileBlock, E_POINTER); m_version = pDbFileBlock->version; m_nRecTypes = pDbFileBlock->nRecTypes; // Allocate record arrays if (NULL == m_RecInfo) { Size = m_nRecTypes * sizeof(IDB_REC_INFO); m_RecInfo = (IDB_REC_INFO*)WsbAlloc(Size); WsbAffirm(m_RecInfo, E_OUTOFMEMORY); ZeroMemory(m_RecInfo, Size); } if (NULL == pDbInfo->RecInfo) { Size = m_nRecTypes * sizeof(IMP_REC_INFO); pDbInfo->RecInfo = (IMP_REC_INFO*)WsbAlloc(Size); WsbAffirm(pDbInfo->RecInfo, E_OUTOFMEMORY); ZeroMemory(pDbInfo->RecInfo, Size); } } WsbCatch(hr); return(hr); } // db_info_to_file_block - copy data to DB info file block HRESULT CWsbDb::db_info_to_file_block(void* block) { HRESULT hr = S_OK; try { FILE_DB_INFO *pDbFileBlock = (FILE_DB_INFO*)block; WsbAssert (0 != pDbFileBlock, E_POINTER); pDbFileBlock->version = m_version; pDbFileBlock->nRecTypes = m_nRecTypes; } WsbCatch(hr); return hr; } // rec_info_from_file_block - copy record data from rec info file block HRESULT CWsbDb::rec_info_from_file_block(int index, void* block) { HRESULT hr = S_OK; try { IMP_DB_INFO* pDbInfo; ULONG Size; FILE_REC_INFO *pRecFileBlock = (FILE_REC_INFO*)block; WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; WsbAssert (0 != pRecFileBlock, E_POINTER); m_RecInfo[index].Type = pRecFileBlock->Type; m_RecInfo[index].EntityClassId = pRecFileBlock->EntityClassId; m_RecInfo[index].Flags = pRecFileBlock->Flags; m_RecInfo[index].MinSize = pRecFileBlock->MinSize; m_RecInfo[index].MaxSize = pRecFileBlock->MaxSize; m_RecInfo[index].nKeys = pRecFileBlock->nKeys; // Allocate Key arrays if (NULL == m_RecInfo[index].Key) { Size = m_RecInfo[index].nKeys * sizeof(IDB_KEY_INFO); m_RecInfo[index].Key = (IDB_KEY_INFO*)WsbAlloc(Size); WsbAffirm(m_RecInfo[index].Key, E_OUTOFMEMORY); ZeroMemory(m_RecInfo[index].Key, Size); } if (NULL == pDbInfo->RecInfo[index].Key) { Size = m_RecInfo[index].nKeys * sizeof(IMP_KEY_INFO); pDbInfo->RecInfo[index].Key = (IMP_KEY_INFO*)WsbAlloc(Size); WsbAffirm(pDbInfo->RecInfo[index].Key, E_OUTOFMEMORY); ZeroMemory(pDbInfo->RecInfo[index].Key, Size); } for (int j = 0; j < pRecFileBlock->nKeys; j++) { m_RecInfo[index].Key[j].Type = pRecFileBlock->Key[j].Type; m_RecInfo[index].Key[j].Size = pRecFileBlock->Key[j].Size; m_RecInfo[index].Key[j].Flags = pRecFileBlock->Key[j].Flags; } } WsbCatch(hr); return(hr); } // rec_info_to_file_block - copy record data to rec info file block HRESULT CWsbDb::rec_info_to_file_block(int index, void* block) { HRESULT hr = S_OK; try { FILE_REC_INFO *pRecFileBlock = (FILE_REC_INFO*)block; WsbAssert (0 != pRecFileBlock, E_POINTER); // pRecFileBlock->SeqNum = m_RecInfo[index].SeqNum; pRecFileBlock->Type = m_RecInfo[index].Type; pRecFileBlock->EntityClassId = m_RecInfo[index].EntityClassId; pRecFileBlock->Flags = m_RecInfo[index].Flags; pRecFileBlock->MinSize = m_RecInfo[index].MinSize; pRecFileBlock->MaxSize = m_RecInfo[index].MaxSize; pRecFileBlock->nKeys = m_RecInfo[index].nKeys; for (int j = 0; j < pRecFileBlock->nKeys; j++) { pRecFileBlock->Key[j].Type = m_RecInfo[index].Key[j].Type; pRecFileBlock->Key[j].Size = m_RecInfo[index].Key[j].Size; pRecFileBlock->Key[j].Flags = m_RecInfo[index].Key[j].Flags; } } WsbCatch(hr); return hr; } // session_current_index - find the index into the session info array. // Sets m_SessionIndex if it's OK HRESULT CWsbDb::session_current_index(IWsbDbSession* pSession) { HRESULT hr = WSB_E_INVALID_DATA; IMP_DB_INFO* pDbInfo; CComQIPtr pSessionPriv = pSession; WsbTraceIn(OLESTR("CWsbDB::session_current_index"), OLESTR("")); pDbInfo = (IMP_DB_INFO*)m_pImp; if (NULL != pDbInfo && NULL != pDbInfo->SessionInfo && pSessionPriv) { JET_SESID SessionId; if (S_OK == pSessionPriv->GetJetId(&SessionId)) { for (int index = 0; index < pDbInfo->nSessions; index++) { if (pDbInfo->SessionInfo[index].SessionId == SessionId) { hr = S_OK; m_SessionIndex = index; break; } } } } WsbTraceOut(OLESTR("CWsbDB::session_current_index"), OLESTR("sessionID[%ld] = %lx"), m_SessionIndex, pDbInfo->SessionInfo[m_SessionIndex].SessionId); return(hr); } // jet_init - make sure this IDB object is initialized for JET HRESULT CWsbDb::jet_init(void) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("CWsbDb::jet_init"), OLESTR("")); try { IMP_DB_INFO* pDbInfo; pDbInfo = (IMP_DB_INFO*)m_pImp; WsbTrace(OLESTR("CWsbDB::jet_init, nSessions = %d\n"), (int)pDbInfo->nSessions); if (0 == pDbInfo->nSessions) { ULONG memSize; // Allocate the thread info array WsbAffirm(m_pWsbDbSys, E_FAIL); memSize = SESSION_INFO_INITIAL_SIZE * sizeof(IMP_SESSION_INFO); pDbInfo->SessionInfo = (IMP_SESSION_INFO*)WsbAlloc(memSize); WsbAffirm(pDbInfo->SessionInfo, E_OUTOFMEMORY); pDbInfo->nSessions = SESSION_INFO_INITIAL_SIZE; ZeroMemory(pDbInfo->SessionInfo, memSize); WsbTrace(OLESTR("CWsbDB::jet_init, SessionInfo(%ld bytes) allocated & zeroed\n"), memSize); // Begin a JET session for the IDB m_SessionIndex = 0; JET_SESID sid; CComPtr pSession; WsbAffirmHr(m_pWsbDbSys->GetGlobalSession(&pSession)); CComQIPtr pSessionPriv = pSession; WsbAffirmPointer(pSessionPriv); WsbAffirmHr(pSessionPriv->GetJetId(&sid)); pDbInfo->SessionInfo[m_SessionIndex].SessionId = sid; WsbTrace(OLESTR("CWsbDB::jet_init, SessionId[0] = %lx\n"), pDbInfo->SessionInfo[m_SessionIndex].SessionId); } } WsbCatch(hr); WsbTraceOut(OLESTR("CWsbDb::jet_init"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // jet_load_info - load DB info from database HRESULT CWsbDb::jet_load_info(void) { HRESULT hr = S_OK; IMP_DB_INFO* pDbInfo = NULL; JET_TABLEID table_id = 0; JET_ERR jstat; WsbTraceIn(OLESTR("CWsbDb::jet_load_info"), OLESTR("")); try { JET_COLUMNID col_id_data; ULONG size; FILE_DB_INFO db_file_block; // Used to move info to/from file FILE_REC_INFO rec_file_block; // Used to move record info WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; // Open the info table jstat = JetOpenTable(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME, NULL, 0, 0, &table_id); if (jstat != JET_errSuccess) { table_id = 0; } WsbTrace(OLESTR("CWsbDb::jet_load_info: open TableId = %ld\n"), table_id); WsbAffirmHr(jet_error(jstat)); WsbAffirmHr(jet_get_column_id(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME, JET_DATA_COLUMN_NAME, &col_id_data)); jstat = JetSetCurrentIndex(JET_CURRENT_SESSION, table_id, NULL); WsbAffirmHr(jet_error(jstat)); // Get the DB info and check for match jstat = JetRetrieveColumn(JET_CURRENT_SESSION, table_id, col_id_data, &db_file_block, sizeof(FILE_DB_INFO), &size, 0, NULL); WsbAffirmHr(jet_error(jstat)); WsbAffirm(db_file_block.nRecTypes > 0, WSB_E_INVALID_DATA); WsbAffirm(db_file_block.version == m_version, WSB_E_IDB_WRONG_VERSION); WsbAffirmHr(db_info_from_file_block(&db_file_block)); // Get the record/key info for (int i = 0; i < m_nRecTypes; i++) { jstat = JetMove(JET_CURRENT_SESSION, table_id, JET_MoveNext, 0); WsbAffirmHr(jet_error(jstat)); jstat = JetRetrieveColumn(JET_CURRENT_SESSION, table_id, col_id_data, &rec_file_block, sizeof(FILE_REC_INFO), &size, 0, NULL); WsbAffirmHr(jet_error(jstat)); WsbAffirmHr(rec_info_from_file_block(i, &rec_file_block)); } } WsbCatch(hr); if (table_id) { jstat = JetCloseTable(JET_CURRENT_SESSION, table_id); WsbTrace(OLESTR("CWsbDb::jet_load_info: close TableId = %ld, jstat = %ld\n"), table_id, jstat); } WsbTraceOut(OLESTR("CWsbDb::jet_load_info"), OLESTR("hr =<%ls>"), WsbHrAsString(hr)); return(hr); } // jet_make_index_name - convert key type to index name HRESULT CWsbDb::jet_make_index_name(ULONG key_type, char* pName, ULONG bufsize) { HRESULT hr = E_FAIL; char lbuf[20]; if (pName != NULL) { sprintf(lbuf, "%ld", key_type); if (bufsize > strlen(lbuf)) { strcpy(pName, lbuf); hr = S_OK; } } return(hr); } // jet_make_table_name - convert record type to table name HRESULT CWsbDb::jet_make_table_name(ULONG rec_type, char* pName, ULONG bufsize) { HRESULT hr = E_FAIL; char lbuf[20]; if (pName != NULL) { sprintf(lbuf, "%ld", rec_type); if (bufsize > strlen(lbuf)) { strcpy(pName, lbuf); hr = S_OK; } } return(hr); } // jet_save_info - save DB info to database HRESULT CWsbDb::jet_save_info() { HRESULT hr = S_OK; IMP_DB_INFO* pDbInfo = NULL; JET_TABLEID table_id = 0; JET_ERR jstat; try { JET_COLUMNID col_id_data; JET_COLUMNID col_id_index; SHORT data_number; FILE_DB_INFO db_file_block; // Used to move info to/from file FILE_REC_INFO rec_file_block; // Used to move record info WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED); pDbInfo = (IMP_DB_INFO*)m_pImp; // Open the table jstat = JetOpenTable(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME, NULL, 0, 0, &table_id); WsbTrace(OLESTR("CWsbDb::jet_save_info: open TableId = %ld\n"), table_id); WsbAffirmHr(jet_error(jstat)); WsbAffirmHr(jet_get_column_id(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME, JET_INDEX_COLUMN_NAME, &col_id_index)); WsbAffirmHr(jet_get_column_id(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME, JET_DATA_COLUMN_NAME, &col_id_data)); // Put the DB info jstat = JetPrepareUpdate(JET_CURRENT_SESSION, table_id, JET_prepInsert); WsbAffirmHr(jet_error(jstat)); WsbAffirmHr(db_info_to_file_block(&db_file_block)); data_number = 0; jstat = JetSetColumn(JET_CURRENT_SESSION, table_id, col_id_index, &data_number, sizeof(data_number), 0, NULL); WsbAffirmHr(jet_error(jstat)); jstat = JetSetColumn(JET_CURRENT_SESSION, table_id, col_id_data, &db_file_block, sizeof(FILE_DB_INFO), 0, NULL); WsbAffirmHr(jet_error(jstat)); jstat = JetUpdate(JET_CURRENT_SESSION, table_id, NULL, 0, NULL); WsbAffirmHr(jet_error(jstat)); // Put the record/key info for (int i = 0; i < m_nRecTypes; i++) { jstat = JetPrepareUpdate(JET_CURRENT_SESSION, table_id, JET_prepInsert); WsbAffirmHr(jet_error(jstat)); WsbAffirmHr(rec_info_to_file_block(i, &rec_file_block)); data_number = (SHORT) ( i + 1 ); jstat = JetSetColumn(JET_CURRENT_SESSION, table_id, col_id_index, &data_number, sizeof(data_number), 0, NULL); WsbAffirmHr(jet_error(jstat)); jstat = JetSetColumn(JET_CURRENT_SESSION, table_id, col_id_data, &rec_file_block, sizeof(FILE_REC_INFO), 0, NULL); WsbAffirmHr(jet_error(jstat)); jstat = JetUpdate(JET_CURRENT_SESSION, table_id, NULL, 0, NULL); WsbAffirmHr(jet_error(jstat)); } } WsbCatch(hr); if (table_id) { jstat = JetCloseTable(JET_CURRENT_SESSION, table_id); WsbTrace(OLESTR("CWsbDb::jet_save_info: close TableId = %ld, jstat = %ld\n"), table_id, jstat); } return(hr); } // Local functions // jet_get_column_id - convert a column name to a column ID static HRESULT jet_get_column_id(JET_SESID jet_session, JET_DBID DbId, char* pTableName, char* pColumnName, JET_COLUMNID* pColId) { HRESULT hr = S_OK; WsbTraceIn(OLESTR("jet_get_column_id"), OLESTR("SessId = %lx, DbId = %lx"), (ULONG)jet_session, (ULONG)DbId); try { JET_COLUMNBASE col_base; JET_ERR jstat; WsbAssert(NULL != pColId, E_POINTER); jstat = JetGetColumnInfo(jet_session, DbId, pTableName, pColumnName, &col_base, sizeof(col_base), JET_ColInfoBase); WsbAssertHr(jet_error(jstat)); *pColId = col_base.columnid; } WsbCatch(hr); WsbTraceOut(OLESTR("jet_get_column_id"), OLESTR("col_id = %ld"), (LONG)*pColId); return(hr); }