windows-nt/Source/XPSP1/NT/base/fs/hsm/idb/wsbdb.cpp
2020-09-26 16:20:57 +08:00

1844 lines
59 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
© 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 <mbstring.h>
#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<IWsbDbSysPriv, &IID_IWsbDbSysPriv> 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<IWsbDbSysPriv, &IID_IWsbDbSysPriv> 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<OLECHAR*>(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<IWsbDbSession> pSession;
WsbTraceIn(OLESTR("CWsbDb::Dump"), OLESTR("path = <%ls>"), Filename);
try {
DWORD CreateFlags;
int i;
int index;
CComPtr<IWsbDbEntity> pIRec;
CComPtr<IStream> 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<WCHAR *>(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<IWsbDbSysPriv, &IID_IWsbDbSysPriv> 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<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> 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<IWsbDbSysPriv, &IID_IWsbDbSysPriv> 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<IWsbDbEntityPriv> pEntity;
WsbTraceIn(OLESTR("CWsbDb::GetEntity"), OLESTR(""));
try {
CComQIPtr<IWsbDb, &IID_IWsbDb> 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<IWsbDb, &IID_IWsbDb> 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<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> 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<IWsbDbSession> pSession;
WsbAffirmHr(m_pWsbDbSys->GetGlobalSession(&pSession));
CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> 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);
}