Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1843 lines
60 KiB

  1. /*++
  2. 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. Wsbdb.cpp
  5. Abstract:
  6. These classes provide support for data bases.
  7. Author:
  8. Ron White [ronw] 19-Nov-1996
  9. Revision History:
  10. --*/
  11. #include "stdafx.h"
  12. #include "wsbdbsys.h"
  13. #include "wsbdbses.h"
  14. #include "wsbdbkey.h"
  15. #include <mbstring.h>
  16. #define JET_DATA_COLUMN_NAME "Data"
  17. #define JET_INDEX_COLUMN_NAME "Index"
  18. #define JET_INFO_TABLE_NAME "Info"
  19. #define JET_SEQNUM_COLUMN_NAME "SeqNum"
  20. #define SESSION_INFO_INITIAL_SIZE 4
  21. #define SESSION_INFO_EXPANSION 6
  22. #define JET_CURRENT_SESSION (pDbInfo->SessionInfo[m_SessionIndex].SessionId)
  23. #define JET_CURRENT_DB (pDbInfo->SessionInfo[m_SessionIndex].DbId)
  24. #define CATCH_ANY_EXCEPTION catch (...) { \
  25. WsbTraceAndLogEvent(WSB_MESSAGE_IDB_EXCEPTION, 0, NULL, NULL); \
  26. WsbTrace(OLESTR("GetLastError = %ld\n"), GetLastError()); \
  27. hr = WSB_E_IDB_EXCEPTION; }
  28. // Local stuff
  29. // These structures hold extra implementation data
  30. typedef struct {
  31. } IMP_KEY_INFO;
  32. typedef struct {
  33. IMP_KEY_INFO* Key;
  34. } IMP_REC_INFO;
  35. // IMP_TABLE_INFO holds information for each open table
  36. typedef struct {
  37. JET_TABLEID TableId;
  38. JET_COLUMNID ColId;
  39. } IMP_TABLE_INFO;
  40. // IMP_SESSION_INFO holds information for each thread
  41. typedef struct {
  42. JET_SESID SessionId; // The Jet session
  43. JET_DBID DbId; // The session's DB ID for this DB
  44. IMP_TABLE_INFO* pTableInfo; // Array of table information
  45. } IMP_SESSION_INFO;
  46. typedef struct {
  47. BOOL IsLoaded; // DB info is loaded into memory
  48. USHORT OpenCount; // Open ref. count
  49. IMP_REC_INFO* RecInfo; // Array of record info
  50. SHORT nSessions;
  51. IMP_SESSION_INFO* SessionInfo;
  52. } IMP_DB_INFO;
  53. // These structures are saved in the data file
  54. typedef struct {
  55. ULONG Type; // Key type ID
  56. ULONG Size; // Key size in bytes
  57. ULONG Flags; // IDB_KEY_FLAG_* flags
  58. } FILE_KEY_INFO;
  59. typedef struct {
  60. ULONG Type; // Record type ID
  61. CLSID EntityClassId; // Derived entity class ID
  62. ULONG Flags; // IDB_REC_FLAG_* flags
  63. ULONG MinSize; // (Minimum) record size in bytes
  64. ULONG MaxSize; // Maximum record size
  65. USHORT nKeys; // Number of keys in this record type
  66. FILE_KEY_INFO Key[IDB_MAX_KEYS_PER_REC];
  67. } FILE_REC_INFO;
  68. typedef struct {
  69. USHORT nRecTypes; // Number of record types
  70. ULONG version; // DB version
  71. } FILE_DB_INFO;
  72. //***************************************************************
  73. // Local function prototypes
  74. static HRESULT jet_get_column_id(JET_SESID jet_session, JET_DBID DbId,
  75. char* pTableName, char* pColumnName, JET_COLUMNID* pColId);
  76. //***************************************************************
  77. // Function definitions
  78. HRESULT
  79. CWsbDb::Create(
  80. IN OLECHAR* path,
  81. ULONG flags
  82. )
  83. /*++
  84. Implements:
  85. IWsbDb::Create
  86. --*/
  87. {
  88. HRESULT hr = S_OK;
  89. IMP_DB_INFO* pDbInfo = NULL;
  90. WsbTraceIn(OLESTR("CWsbDb::Create"), OLESTR("path = <%ls>"), path);
  91. try {
  92. int key_index;
  93. ULONG memSize;
  94. int rec_index;
  95. WsbAssert(0 != path, E_POINTER);
  96. WsbAssert(0 != m_RecInfo, WSB_E_NOT_INITIALIZED);
  97. WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED);
  98. pDbInfo = (IMP_DB_INFO*)m_pImp;
  99. Lock();
  100. WsbAffirm(!pDbInfo->IsLoaded, WSB_E_NOT_INITIALIZED);
  101. WsbAffirm(!pDbInfo->RecInfo, WSB_E_NOT_INITIALIZED);
  102. // Save the path
  103. m_path = path;
  104. // Check validity of some info that the derived class is
  105. // suppose to supply.
  106. WsbAffirm(m_version != 0, WSB_E_NOT_INITIALIZED);
  107. WsbAffirm(m_nRecTypes > 0, WSB_E_NOT_INITIALIZED);
  108. WsbAffirm(m_nRecTypes <= IDB_MAX_REC_TYPES, WSB_E_INVALID_DATA);
  109. pDbInfo->IsLoaded = TRUE;
  110. // Allocate the RecInfo array
  111. memSize = m_nRecTypes * sizeof(IMP_REC_INFO);
  112. pDbInfo->RecInfo = (IMP_REC_INFO*)WsbAlloc(memSize);
  113. WsbAffirm(pDbInfo->RecInfo, E_OUTOFMEMORY);
  114. ZeroMemory(pDbInfo->RecInfo, memSize);
  115. char index_names[IDB_MAX_KEYS_PER_REC + 1][20];
  116. JET_COLUMNCREATE jet_columns[IDB_MAX_KEYS_PER_REC + 2];
  117. JET_INDEXCREATE jet_indices[IDB_MAX_KEYS_PER_REC + 1];
  118. JET_TABLECREATE jet_table;
  119. JET_ERR jstat;
  120. char key_names[IDB_MAX_KEYS_PER_REC + 1][22];
  121. char* name;
  122. char table_name[20];
  123. JET_GRBIT createFlags = 0;
  124. // Start a Jet session for this thread
  125. WsbAffirmHr(jet_init());
  126. // Make sure there's room for another DB
  127. CComQIPtr<IWsbDbSysPriv, &IID_IWsbDbSysPriv> pDbSysPriv = m_pWsbDbSys;
  128. WsbAffirmPointer(pDbSysPriv);
  129. WsbAffirmHr(pDbSysPriv->DbAttachedAdd(path, FALSE));
  130. // Set creation flag
  131. if (flags & IDB_CREATE_FLAG_NO_TRANSACTION) {
  132. // Setting this flag stil allow transaction calls - they are just being ignored and MT-safe is not guaranteed
  133. createFlags |= (JET_bitDbVersioningOff & JET_bitDbRecoveryOff);
  134. }
  135. // Create the DB
  136. WsbAffirmHr(wsb_db_jet_fix_path(path, L"." IDB_DB_FILE_SUFFIX, &name));
  137. jstat = JetCreateDatabase(JET_CURRENT_SESSION, name, NULL, &JET_CURRENT_DB, createFlags);
  138. WsbTrace(OLESTR("JetCreateDB = %ld\n"), (LONG)jstat);
  139. WsbFree(name);
  140. WsbAffirmHr(jet_error(jstat));
  141. // Set up constant part of table structure
  142. jet_table.cbStruct = sizeof(JET_TABLECREATE);
  143. jet_table.szTemplateTableName = NULL;
  144. jet_table.ulPages = 4; // ????
  145. jet_table.ulDensity = 50; // ?????
  146. jet_table.rgcolumncreate = jet_columns;
  147. jet_table.rgindexcreate = jet_indices;
  148. jet_table.grbit = 0;
  149. // Set up the constant part of the column structures
  150. ZeroMemory(&jet_columns, sizeof(jet_columns));
  151. ZeroMemory(&jet_indices, sizeof(jet_indices));
  152. jet_columns[0].cbStruct = sizeof(JET_COLUMNCREATE);
  153. jet_columns[0].szColumnName = JET_DATA_COLUMN_NAME;
  154. jet_columns[1].cbStruct = sizeof(JET_COLUMNCREATE);
  155. // Create a "table" to hold info about this DB
  156. jet_table.szTableName = JET_INFO_TABLE_NAME;
  157. jet_table.cColumns = 2;
  158. jet_table.cIndexes = 1;
  159. jet_columns[0].coltyp = JET_coltypLongBinary;
  160. jet_columns[0].cbMax = sizeof(FILE_REC_INFO);
  161. jet_columns[1].szColumnName = JET_INDEX_COLUMN_NAME;
  162. jet_columns[1].coltyp = JET_coltypShort;
  163. jet_columns[1].cbMax = sizeof(SHORT);
  164. jet_indices[0].cbStruct = sizeof(JET_INDEXCREATE);
  165. jet_indices[0].szIndexName = JET_INDEX_COLUMN_NAME;
  166. ZeroMemory(key_names[0], 22);
  167. sprintf(key_names[0], "+%s", JET_INDEX_COLUMN_NAME);
  168. jet_indices[0].szKey = key_names[0];
  169. jet_indices[0].cbKey = strlen(key_names[0]) + 2;
  170. jet_indices[0].grbit |= JET_bitIndexPrimary;
  171. jet_indices[0].ulDensity = 90;
  172. jstat = JetCreateTableColumnIndex(JET_CURRENT_SESSION, JET_CURRENT_DB, &jet_table);
  173. WsbTrace(OLESTR("CWsbDb::Create: JetCreateTableColumnIndex status = %ld\n"), jstat);
  174. if (JET_errSuccess != jstat) {
  175. WsbTrace(OLESTR("CWsbDb::Create: JetCreateTableColumnIndex, cCreated = %ld\n"), jet_table.cCreated);
  176. }
  177. WsbAffirmHr(jet_error(jstat));
  178. jstat = JetCloseTable(JET_CURRENT_SESSION, jet_table.tableid);
  179. WsbTrace(OLESTR("CWsbDb::Create: close TableId = %ld, jstat = %ld\n"),
  180. jet_table.tableid, jstat);
  181. // Write DB info
  182. jstat = JetBeginTransaction(JET_CURRENT_SESSION);
  183. WsbTrace(OLESTR("CWsbDb::Create: JetBeginTransaction = %ld\n"), jstat);
  184. jstat = jet_save_info();
  185. if (JET_errSuccess == jstat) {
  186. jstat = JetCommitTransaction(JET_CURRENT_SESSION, 0);
  187. WsbTrace(OLESTR("CWsbDb::Create: JetCommitTransaction = %ld\n"), jstat);
  188. } else {
  189. HRESULT hr2 = jet_error(jstat);
  190. jstat = JetRollback(JET_CURRENT_SESSION, 0);
  191. WsbTrace(OLESTR("CWsbDb::Create: JetRollback = %ld\n"), jstat);
  192. WsbThrow(hr2);
  193. }
  194. // We create a table for each record type. The first column of each
  195. // table is the record (stored as a blob). The second column is a
  196. // unique sequence number for each record. The rest of the columns are for
  197. // key values used as indices.
  198. jet_columns[1].szColumnName = JET_SEQNUM_COLUMN_NAME;
  199. jet_columns[1].coltyp = JET_coltypLong;
  200. jet_columns[1].cbMax = sizeof(ULONG);
  201. jet_columns[1].grbit = JET_bitColumnAutoincrement;
  202. jet_indices[0].cbStruct = sizeof(JET_INDEXCREATE);
  203. strcpy(index_names[0], JET_SEQNUM_COLUMN_NAME);
  204. jet_indices[0].szIndexName = index_names[0];
  205. ZeroMemory(key_names[0], 22);
  206. sprintf(key_names[0], "+%s", index_names[0]);
  207. jet_indices[0].szKey = key_names[0];
  208. jet_indices[0].cbKey = strlen(key_names[0]) + 2;
  209. jet_indices[0].grbit = 0;
  210. jet_indices[0].ulDensity = 90;
  211. // Loop over record types
  212. for (rec_index = 0; rec_index < m_nRecTypes; rec_index++) {
  213. WsbAffirm(m_RecInfo[rec_index].Type > 0, WSB_E_NOT_INITIALIZED);
  214. WsbAffirm(m_RecInfo[rec_index].nKeys > 0, WSB_E_NOT_INITIALIZED);
  215. WsbAffirm(m_RecInfo[rec_index].nKeys <= IDB_MAX_KEYS_PER_REC, WSB_E_INVALID_DATA);
  216. // Allocate the Key array
  217. memSize = m_RecInfo[rec_index].nKeys * sizeof(IMP_KEY_INFO);
  218. pDbInfo->RecInfo[rec_index].Key = (IMP_KEY_INFO*)WsbAlloc(memSize);
  219. WsbAffirm(pDbInfo->RecInfo[rec_index].Key, E_OUTOFMEMORY);
  220. ZeroMemory(pDbInfo->RecInfo[rec_index].Key, memSize);
  221. // Fill in the table structure with info specific to this
  222. // record type
  223. WsbAffirmHr(jet_make_table_name(m_RecInfo[rec_index].Type, table_name, 20));
  224. jet_table.szTableName = table_name;
  225. jet_table.cColumns = m_RecInfo[rec_index].nKeys + 2;
  226. jet_table.cIndexes = m_RecInfo[rec_index].nKeys + 1;
  227. // Fill in the column structure for the record itself
  228. if (m_RecInfo[rec_index].MaxSize < 255) {
  229. jet_columns[0].coltyp = JET_coltypBinary;
  230. } else {
  231. jet_columns[0].coltyp = JET_coltypLongBinary;
  232. }
  233. jet_columns[0].cbMax = m_RecInfo[rec_index].MaxSize;
  234. // Loop over keys
  235. for (key_index = 0; key_index < m_RecInfo[rec_index].nKeys;
  236. key_index++) {
  237. WsbAffirm(m_RecInfo[rec_index].Key[key_index].Type > 0, WSB_E_NOT_INITIALIZED);
  238. WsbAffirm(m_RecInfo[rec_index].Key[key_index].Size <= IDB_MAX_KEY_SIZE,
  239. WSB_E_NOT_INITIALIZED);
  240. WsbAffirm(!(m_RecInfo[rec_index].Key[key_index].Flags & IDB_KEY_FLAG_PRIMARY) ||
  241. !(m_RecInfo[rec_index].Key[key_index].Flags & IDB_KEY_FLAG_DUP_ALLOWED),
  242. WSB_E_IDB_PRIMARY_UNIQUE);
  243. // Fill in a column structure for each key
  244. jet_columns[key_index + 2].cbStruct = sizeof(JET_COLUMNCREATE);
  245. WsbAffirmHr(jet_make_index_name(m_RecInfo[rec_index].Key[key_index].Type,
  246. index_names[key_index + 1], 20));
  247. jet_columns[key_index + 2].szColumnName = index_names[key_index + 1];
  248. jet_columns[key_index + 2].grbit = JET_bitColumnFixed;
  249. jet_columns[key_index + 2].pvDefault = NULL;
  250. jet_columns[key_index + 2].cbDefault = 0;
  251. if (m_RecInfo[rec_index].Key[key_index].Size < 255) {
  252. jet_columns[key_index + 2].coltyp = JET_coltypBinary;
  253. } else {
  254. jet_columns[key_index + 2].coltyp = JET_coltypLongBinary;
  255. }
  256. jet_columns[key_index + 2].cbMax = m_RecInfo[rec_index].Key[key_index].Size;
  257. // Fill in an index structure for each key
  258. jet_indices[key_index + 1].cbStruct = sizeof(JET_INDEXCREATE);
  259. jet_indices[key_index + 1].szIndexName = index_names[key_index + 1];
  260. ZeroMemory(key_names[key_index + 1], 22);
  261. sprintf(key_names[key_index + 1], "+%s\0", index_names[key_index + 1]);
  262. jet_indices[key_index + 1].szKey = key_names[key_index + 1];
  263. jet_indices[key_index + 1].cbKey = strlen(key_names[key_index + 1]) + 2;
  264. if (m_RecInfo[rec_index].Key[key_index].Flags & IDB_KEY_FLAG_DUP_ALLOWED) {
  265. jet_indices[key_index + 1].grbit = 0;
  266. } else {
  267. jet_indices[key_index + 1].grbit = JET_bitIndexUnique;
  268. }
  269. if (m_RecInfo[rec_index].Key[key_index].Flags & IDB_KEY_FLAG_PRIMARY) {
  270. jet_indices[key_index + 1].grbit |= JET_bitIndexPrimary;
  271. }
  272. jet_indices[key_index + 1].ulDensity = 50;
  273. } // End of key loop
  274. // Set table creation flags
  275. if (flags & IDB_CREATE_FLAG_FIXED_SCHEMA) {
  276. jet_table.grbit |= JET_bitTableCreateFixedDDL;
  277. }
  278. // Create the "table" for each record type; this call defines
  279. // the columns (fields) and index keys
  280. jstat = JetCreateTableColumnIndex(JET_CURRENT_SESSION, JET_CURRENT_DB, &jet_table);
  281. WsbTrace(OLESTR("JetCreateTableColumnIndex = %ld\n"), jstat);
  282. WsbAffirmHr(jet_error(jstat));
  283. jstat = JetCloseTable(JET_CURRENT_SESSION, jet_table.tableid);
  284. WsbTrace(OLESTR("CWsbDb::Create: close TableId = %ld, jstat = %ld\n"),
  285. jet_table.tableid, jstat);
  286. } // End of record loop
  287. jstat = JetCloseDatabase(JET_CURRENT_SESSION, JET_CURRENT_DB, 0);
  288. WsbTrace(OLESTR("CWsbDb::Create: JetCloseDatabase = %ld\n"),
  289. (LONG)jstat);
  290. JET_CURRENT_DB = 0;
  291. pDbInfo->OpenCount = 0;
  292. } WsbCatchAndDo(hr,
  293. WsbLogEvent(WSB_MESSAGE_IDB_CREATE_FAILED, 0, NULL,
  294. WsbAbbreviatePath(path, 120), NULL);
  295. )
  296. CATCH_ANY_EXCEPTION
  297. if (pDbInfo) {
  298. Unlock();
  299. }
  300. WsbTraceOut(OLESTR("CWsbDb::Create"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  301. return(hr);
  302. }
  303. HRESULT
  304. CWsbDb::Delete(
  305. IN OLECHAR *path,
  306. ULONG flags
  307. )
  308. /*++
  309. Implements:
  310. IWsbDb::Delete
  311. --*/
  312. {
  313. HRESULT hr = S_OK;
  314. char* name = NULL;
  315. IMP_DB_INFO* pDbInfo = NULL;
  316. WsbTraceIn(OLESTR("CWsbDb::Delete"), OLESTR("path = <%ls>"),
  317. WsbStringAsString(path));
  318. try {
  319. CWsbStringPtr DeletePath;
  320. WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED);
  321. pDbInfo = (IMP_DB_INFO*)m_pImp;
  322. Lock();
  323. // Can't delete it if it's open
  324. WsbAffirm(pDbInfo->OpenCount == 0, E_UNEXPECTED);
  325. if (NULL == path) {
  326. path = m_path;
  327. }
  328. WsbAffirm(path && wcslen(path), S_FALSE);
  329. WsbAffirmHr(wsb_db_jet_fix_path(path, L"." IDB_DB_FILE_SUFFIX, &name));
  330. // Detach (if attached)
  331. CComQIPtr<IWsbDbSysPriv, &IID_IWsbDbSysPriv> pDbSysPriv = m_pWsbDbSys;
  332. WsbAffirmPointer(pDbSysPriv);
  333. WsbAffirmHr(pDbSysPriv->DbAttachedRemove(path));
  334. // Now delete it
  335. DeletePath = name;
  336. if (!DeleteFile(DeletePath)) {
  337. DWORD err = GetLastError();
  338. WsbTrace(OLESTR("CWsbDb::Delete: DeleteFile(%ls) failed, error = %ld\n"),
  339. static_cast<OLECHAR*>(DeletePath), err);
  340. WsbThrow(HRESULT_FROM_WIN32(err));
  341. }
  342. // Put message in event log
  343. if (flags & IDB_DELETE_FLAG_NO_ERROR) {
  344. WsbLogEvent(WSB_E_IDB_DATABASE_DELETED_NO_ERROR, 0, NULL,
  345. WsbAbbreviatePath(DeletePath, 120), NULL);
  346. } else {
  347. WsbLogEvent(WSB_E_IDB_DATABASE_DELETED, 0, NULL,
  348. WsbAbbreviatePath(DeletePath, 120), NULL);
  349. }
  350. }
  351. WsbCatch(hr)
  352. if (pDbInfo) {
  353. Unlock();
  354. }
  355. if (name) {
  356. WsbFree(name);
  357. }
  358. WsbTraceOut(OLESTR("CWsbDb::Delete"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  359. return(hr);
  360. }
  361. HRESULT
  362. CWsbDb::Dump(
  363. IN OLECHAR* Filename,
  364. IN ULONG Flags,
  365. IN ULONG Data
  366. )
  367. /*++
  368. Implements:
  369. IWsbDb::Dump
  370. --*/
  371. {
  372. HANDLE hFile = 0;
  373. HRESULT hr = S_OK;
  374. IMP_DB_INFO* pDbInfo = NULL;
  375. CComPtr<IWsbDbSession> pSession;
  376. WsbTraceIn(OLESTR("CWsbDb::Dump"), OLESTR("path = <%ls>"), Filename);
  377. try {
  378. DWORD CreateFlags;
  379. int i;
  380. int index;
  381. CComPtr<IWsbDbEntity> pIRec;
  382. CComPtr<IStream> pStream;
  383. WsbAssert(0 != Filename, E_POINTER);
  384. WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED);
  385. pDbInfo = (IMP_DB_INFO*)m_pImp;
  386. Lock();
  387. // WsbAffirmHr(session_current_index(Session));
  388. // Open the Db
  389. // SteveW
  390. // added code to ensure that a database was opened
  391. // if not go on to the next database, but do not
  392. // throw an exception.
  393. //
  394. hr = Open(&pSession);
  395. if (hr == S_OK) {
  396. // Open/create the output file
  397. if (Flags & IDB_DUMP_FLAG_APPEND_TO_FILE) {
  398. CreateFlags = OPEN_ALWAYS;
  399. } else {
  400. CreateFlags = CREATE_ALWAYS;
  401. }
  402. hFile = CreateFile(Filename, GENERIC_WRITE, FILE_SHARE_READ, NULL,
  403. CreateFlags, FILE_ATTRIBUTE_NORMAL, NULL);
  404. WsbAffirmHandle(hFile);
  405. if (Flags & IDB_DUMP_FLAG_APPEND_TO_FILE) {
  406. // Position to the end of the file
  407. SetFilePointer(hFile, 0, NULL, FILE_END);
  408. }
  409. // Create the output stream
  410. WsbAffirmHr(CreateStreamOnHGlobal(NULL, TRUE, &pStream));
  411. // Dump general DB info
  412. if (Flags & IDB_DUMP_FLAG_DB_INFO) {
  413. WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("Dump of DB: %ls\n"),
  414. static_cast<WCHAR *>(m_path)));
  415. WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR(" version = %ld, # record types = %d\n"),
  416. m_version, m_nRecTypes));
  417. WsbAffirmHr(WsbStreamToFile(hFile, pStream, TRUE));
  418. }
  419. // Loop over record types
  420. for (i = 0; i < m_nRecTypes; i++) {
  421. // Dump record info
  422. if (Flags & IDB_DUMP_FLAG_REC_INFO) {
  423. WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("RecType = %8ld, Flags = %0.8lx, "),
  424. m_RecInfo[i].Type, m_RecInfo[i].Flags));
  425. WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("MaxSize = %8ld, # keys = %4d\n"),
  426. m_RecInfo[i].MaxSize, m_RecInfo[i].nKeys));
  427. WsbAffirmHr(WsbStreamToFile(hFile, pStream, TRUE));
  428. }
  429. // Dump key info
  430. if (Flags & IDB_DUMP_FLAG_KEY_INFO) {
  431. for (int j = 0; j < m_RecInfo[i].nKeys; j++) {
  432. WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR(" KeyType = %8ld, Size = %8ld, Flags = %0.8lx\n"),
  433. m_RecInfo[i].Key[j].Type, m_RecInfo[i].Key[j].Size, m_RecInfo[i].Key[j].Flags));
  434. }
  435. WsbAffirmHr(WsbStreamToFile(hFile, pStream, TRUE));
  436. }
  437. }
  438. // Dump records
  439. if (Flags & (IDB_DUMP_FLAG_RECORDS | IDB_DUMP_FLAG_RECORD_TYPE)) {
  440. for (i = 0; i < m_nRecTypes; i++) {
  441. if (!(Flags & IDB_DUMP_FLAG_RECORDS) &&
  442. m_RecInfo[i].Type != Data) {
  443. continue;
  444. }
  445. WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("\n*** Dump of records of Type = %ld ***\n"),
  446. m_RecInfo[i].Type));
  447. // Get a DB entity
  448. pIRec = 0;
  449. WsbAffirmHr(GetEntity(pSession, m_RecInfo[i].Type, IID_IWsbDbEntity,
  450. (void**)&pIRec));
  451. // Loop over records
  452. index = 0;
  453. hr = pIRec->First();
  454. while (S_OK == hr) {
  455. WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("%0.5d "), index));
  456. WsbAffirmHr(pIRec->Print(pStream));
  457. WsbAffirmHr(WsbPrintfToStream(pStream, OLESTR("\n")));
  458. WsbAffirmHr(WsbStreamToFile(hFile, pStream, TRUE));
  459. hr = pIRec->Next();
  460. index++;
  461. }
  462. if (WSB_E_NOTFOUND == hr) {
  463. hr = S_OK;
  464. } else {
  465. WsbAffirmHr(hr);
  466. }
  467. }
  468. }
  469. }
  470. } WsbCatch(hr)
  471. CATCH_ANY_EXCEPTION
  472. if (hFile) {
  473. CloseHandle(hFile);
  474. }
  475. if (pSession) {
  476. Close(pSession);
  477. }
  478. if (pDbInfo) {
  479. Unlock();
  480. }
  481. WsbTraceOut(OLESTR("CWsbDb::Dump"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  482. return(hr);
  483. }
  484. HRESULT
  485. CWsbDb::Locate(
  486. IN OLECHAR *path
  487. )
  488. /*++
  489. Implements:
  490. IWsbDb::Locate
  491. --*/
  492. {
  493. HRESULT hr = S_OK;
  494. IMP_DB_INFO* pDbInfo = NULL;
  495. WsbTraceIn(OLESTR("CWsbDb::Locate"), OLESTR("path = <%ls>"), path);
  496. try {
  497. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  498. pDbInfo = (IMP_DB_INFO*)m_pImp;
  499. Lock();
  500. WsbAffirm(pDbInfo->OpenCount == 0, E_UNEXPECTED);
  501. m_path = path;
  502. JET_ERR jstat;
  503. char* name;
  504. // Start a Jet session for this thread
  505. WsbAffirmHr(jet_init());
  506. WsbAffirmHr(wsb_db_jet_fix_path(path, L"." IDB_DB_FILE_SUFFIX, &name));
  507. hr = S_OK;
  508. try {
  509. CComQIPtr<IWsbDbSysPriv, &IID_IWsbDbSysPriv> pDbSysPriv = m_pWsbDbSys;
  510. WsbAffirmPointer(pDbSysPriv);
  511. WsbAffirmHr(pDbSysPriv->DbAttachedAdd(path, TRUE));
  512. jstat = JetOpenDatabase(JET_CURRENT_SESSION, name, NULL, &JET_CURRENT_DB, 0);
  513. if (jstat == JET_errDatabaseNotFound) {
  514. WsbThrow(STG_E_FILENOTFOUND);
  515. } else {
  516. WsbAffirmHr(jet_error(jstat));
  517. }
  518. } WsbCatch(hr);
  519. WsbFree(name);
  520. WsbAffirmHr(hr);
  521. // Load information about this DB
  522. hr = jet_load_info();
  523. jstat = JetCloseDatabase(JET_CURRENT_SESSION, JET_CURRENT_DB, 0);
  524. WsbTrace(OLESTR("CWsbDb::Locate: JetCloseDatabase = %ld\n"),
  525. (LONG)jstat);
  526. JET_CURRENT_DB = 0;
  527. pDbInfo = (IMP_DB_INFO*)m_pImp;
  528. pDbInfo->OpenCount = 0;
  529. } WsbCatch(hr)
  530. CATCH_ANY_EXCEPTION
  531. if (pDbInfo) {
  532. Unlock();
  533. }
  534. WsbTraceOut(OLESTR("CWsbDb::Locate"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  535. return(hr);
  536. }
  537. HRESULT
  538. CWsbDb::Open(
  539. OUT IWsbDbSession** ppSession
  540. )
  541. /*++
  542. Implements:
  543. IWsbDb::Open
  544. --*/
  545. {
  546. HRESULT hr = S_OK;
  547. IMP_DB_INFO* pDbInfo = NULL;
  548. WsbTraceIn(OLESTR("CWsbDb::Open"), OLESTR(""));
  549. try {
  550. ULONG Size = 0;
  551. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  552. pDbInfo = (IMP_DB_INFO*)m_pImp;
  553. Lock();
  554. WsbAffirmHr(m_path.GetLen(&Size));
  555. WsbAffirm(Size > 0, WSB_E_NOT_INITIALIZED);
  556. // Make sure we have a session
  557. WsbAffirm(0 != ppSession, E_POINTER);
  558. if (0 == *ppSession) {
  559. WsbAffirmHr(m_pWsbDbSys->NewSession(ppSession));
  560. WsbTrace(OLESTR("CWsbDb::Open: session created\n"));
  561. }
  562. int i;
  563. JET_ERR jstat;
  564. ULONG memSize;
  565. char* name;
  566. JET_SESID SessionId;
  567. int s_index;
  568. IMP_SESSION_INFO* s_info = pDbInfo->SessionInfo;
  569. CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = *ppSession;
  570. WsbAffirm(0 < pDbInfo->nSessions, WSB_E_NOT_INITIALIZED);
  571. WsbAffirm(pSessionPriv, E_FAIL);
  572. // Get the JET session ID
  573. WsbAffirmHr(pSessionPriv->GetJetId(&SessionId));
  574. // We need to save session info; look for an empty slot.
  575. WsbTrace(OLESTR("CWsbDb::Open: nSessions = %d, SessionId = %lx\n"), (
  576. int)pDbInfo->nSessions, SessionId);
  577. s_index = pDbInfo->nSessions;
  578. for (i = 0; i < pDbInfo->nSessions; i++) {
  579. WsbTrace(OLESTR("CWsbDb::Open: s_info[%d] = %lx\n"), i,
  580. s_info[i].SessionId);
  581. // Check for a duplicate session ID already in the table
  582. if (SessionId == s_info[i].SessionId) {
  583. s_index = i;
  584. break;
  585. // Check for an unused slot
  586. } else if (0 == s_info[i].SessionId && 0 == s_info[i].DbId &&
  587. s_index == pDbInfo->nSessions) {
  588. s_index = i;
  589. }
  590. }
  591. WsbTrace(OLESTR("CWsbDb::Open: s_index = %d\n"), s_index);
  592. if (s_index == pDbInfo->nSessions) {
  593. SHORT newNum;
  594. // Didn't find an empty slot; expand the array
  595. newNum = (SHORT) ( s_index + SESSION_INFO_EXPANSION );
  596. WsbTrace(OLESTR("CWsbDb::Open: expanding session table from %d to %d\n"),
  597. s_index, newNum);
  598. memSize = newNum * sizeof(IMP_SESSION_INFO);
  599. s_info = (IMP_SESSION_INFO*)WsbRealloc(pDbInfo->SessionInfo,
  600. memSize);
  601. WsbAffirm(s_info, E_OUTOFMEMORY);
  602. ZeroMemory(&s_info[s_index], SESSION_INFO_EXPANSION *
  603. sizeof(IMP_SESSION_INFO));
  604. pDbInfo->SessionInfo = s_info;
  605. pDbInfo->nSessions = newNum;
  606. }
  607. // Save the session ID and index
  608. m_SessionIndex = s_index;
  609. s_info[s_index].SessionId = SessionId;
  610. WsbTrace(OLESTR("CWsbDB::Open, s_info = %lx, SessionId[%d] = %lx\n"),
  611. (LONG)s_index, m_SessionIndex, JET_CURRENT_SESSION);
  612. WsbAffirmHr(wsb_db_jet_fix_path(m_path, L"." IDB_DB_FILE_SUFFIX, &name));
  613. CComQIPtr<IWsbDbSysPriv, &IID_IWsbDbSysPriv> pDbSysPriv = m_pWsbDbSys;
  614. WsbAffirmPointer(pDbSysPriv);
  615. WsbAffirmHr(pDbSysPriv->DbAttachedAdd(m_path, TRUE));
  616. jstat = JetOpenDatabase(JET_CURRENT_SESSION, name, NULL,
  617. &JET_CURRENT_DB, 0);
  618. WsbFree(name);
  619. if (jstat == JET_errDatabaseNotFound) {
  620. WsbThrow(STG_E_FILENOTFOUND);
  621. } else {
  622. WsbAffirmHr(jet_error(jstat));
  623. }
  624. // Allocate/zero the table info array
  625. memSize = m_nRecTypes * sizeof(IMP_TABLE_INFO);
  626. WsbTrace(OLESTR("CWsbDb::Open: pTableInfo = %lx\n"),
  627. s_info[m_SessionIndex].pTableInfo);
  628. if (NULL == s_info[m_SessionIndex].pTableInfo) {
  629. s_info[m_SessionIndex].pTableInfo = (IMP_TABLE_INFO*)WsbAlloc(memSize);
  630. WsbAffirm(s_info[m_SessionIndex].pTableInfo, E_OUTOFMEMORY);
  631. WsbTrace(OLESTR("CWsbDb::Open: new pTableInfo = %lx\n"),
  632. s_info[m_SessionIndex].pTableInfo);
  633. }
  634. ZeroMemory(s_info[m_SessionIndex].pTableInfo, memSize);
  635. pDbInfo->OpenCount++;
  636. } WsbCatchAndDo(hr,
  637. WsbLogEvent(WSB_MESSAGE_IDB_OPEN_FAILED, 0, NULL,
  638. WsbAbbreviatePath(m_path, 120), NULL);
  639. )
  640. CATCH_ANY_EXCEPTION
  641. if (pDbInfo) {
  642. Unlock();
  643. }
  644. WsbTraceOut(OLESTR("CWsbDb::Open"), OLESTR("hr =<%ls>"),
  645. WsbHrAsString(hr));
  646. return(hr);
  647. }
  648. HRESULT
  649. CWsbDb::Close(
  650. IN IWsbDbSession* pSession
  651. )
  652. /*++
  653. Implements:
  654. IWsbDb::Close
  655. - The element was added.
  656. --*/
  657. {
  658. HRESULT hr = S_OK;
  659. IMP_DB_INFO* pDbInfo = NULL;
  660. WsbTraceIn(OLESTR("CWsbDb::Close"), OLESTR(""));
  661. try {
  662. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  663. pDbInfo = (IMP_DB_INFO*)m_pImp;
  664. Lock();
  665. WsbAffirm(pDbInfo->OpenCount, WSB_E_NOT_INITIALIZED);
  666. WsbAffirmHr(session_current_index(pSession));
  667. pDbInfo->OpenCount--;
  668. JET_ERR jstat;
  669. IMP_SESSION_INFO* s_info = pDbInfo->SessionInfo;
  670. WsbTrace(OLESTR("CWsbDb::Close: closing DB, SessionId = %lx, DbId = %lx\n"),
  671. (LONG)s_info[m_SessionIndex].SessionId, (LONG)s_info[m_SessionIndex].DbId);
  672. jstat = JetCloseDatabase(s_info[m_SessionIndex].SessionId,
  673. s_info[m_SessionIndex].DbId, 0);
  674. WsbTrace(OLESTR("CWsbDb::Close: JetCloseDatabase = %ld\n"),
  675. (LONG)jstat);
  676. if (s_info[m_SessionIndex].pTableInfo) {
  677. WsbTrace(OLESTR("CWsbDb::Close: releasing pTableInfo\n"));
  678. WsbFree(s_info[m_SessionIndex].pTableInfo);
  679. s_info[m_SessionIndex].pTableInfo = NULL;
  680. }
  681. s_info[m_SessionIndex].SessionId = 0;
  682. s_info[m_SessionIndex].DbId = 0;
  683. } WsbCatch(hr)
  684. CATCH_ANY_EXCEPTION
  685. if (pDbInfo) {
  686. Unlock();
  687. }
  688. WsbTraceOut(OLESTR("CWsbDb::Close"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  689. return(hr);
  690. }
  691. HRESULT
  692. CWsbDb::GetEntity(
  693. IN IWsbDbSession* pSession,
  694. IN ULONG RecId,
  695. IN REFIID riid,
  696. OUT void** ppEntity
  697. )
  698. /*++
  699. Implements:
  700. IWsbDb::GetEntity
  701. --*/
  702. {
  703. HRESULT hr = S_OK;
  704. IMP_DB_INFO* pDbInfo = NULL;
  705. CComPtr<IWsbDbEntityPriv> pEntity;
  706. WsbTraceIn(OLESTR("CWsbDb::GetEntity"), OLESTR(""));
  707. try {
  708. CComQIPtr<IWsbDb, &IID_IWsbDb> pIWsbDb = (IWsbDbPriv*)this;
  709. int rec_index;
  710. WsbAssert(0 != ppEntity, E_POINTER);
  711. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  712. pDbInfo = (IMP_DB_INFO*)m_pImp;
  713. Lock();
  714. WsbAffirmHr(session_current_index(pSession));
  715. // Find the record info
  716. for (rec_index = 0; rec_index < m_nRecTypes; rec_index++) {
  717. if (m_RecInfo[rec_index].Type == RecId) break;
  718. }
  719. WsbAffirm(rec_index < m_nRecTypes, E_INVALIDARG);
  720. // Create the instance, initialize it to point to this DB, and
  721. // return the pointer to the caller.
  722. WsbAffirmHr(CoCreateInstance(m_RecInfo[rec_index].EntityClassId, NULL,
  723. CLSCTX_SERVER | CLSCTX_INPROC_HANDLER,
  724. IID_IWsbDbEntityPriv, (void**) &pEntity));
  725. WsbAffirmHr(pEntity->Init(pIWsbDb, m_pWsbDbSys, RecId, JET_CURRENT_SESSION));
  726. WsbAffirmHr(pEntity->QueryInterface(riid, (void**)ppEntity));
  727. } WsbCatch(hr)
  728. CATCH_ANY_EXCEPTION
  729. if (pDbInfo) {
  730. Unlock();
  731. }
  732. WsbTraceOut(OLESTR("CWsbDb::GetEntity"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  733. return(hr);
  734. }
  735. HRESULT
  736. CWsbDb::GetKeyInfo(
  737. IN ULONG RecType,
  738. IN USHORT nKeys,
  739. OUT COM_IDB_KEY_INFO* pKeyInfo
  740. )
  741. /*++
  742. Implements:
  743. IWsbDbPriv::GetKeyInfo
  744. --*/
  745. {
  746. HRESULT hr = E_FAIL;
  747. WsbTraceIn(OLESTR("CWsbDb::GetKeyInfo"), OLESTR(""));
  748. try {
  749. IMP_DB_INFO* pDbInfo;
  750. WsbAssert(0 < nKeys, E_INVALIDARG);
  751. WsbAssert(0 != pKeyInfo, E_POINTER);
  752. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  753. pDbInfo = (IMP_DB_INFO*)m_pImp;
  754. for (int i = 0; i < m_nRecTypes; i++) {
  755. if (m_RecInfo[i].Type == RecType) {
  756. USHORT n = min(nKeys, m_RecInfo[i].nKeys);
  757. for (int j = 0; j < n; j++) {
  758. pKeyInfo[j].Type = m_RecInfo[i].Key[j].Type;
  759. pKeyInfo[j].Size = m_RecInfo[i].Key[j].Size;
  760. pKeyInfo[j].Flags = m_RecInfo[i].Key[j].Flags;
  761. }
  762. hr = S_OK;
  763. break;
  764. }
  765. }
  766. } WsbCatch(hr);
  767. WsbTraceOut(OLESTR("CWsbDb::GetKeyInfo"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  768. return(hr);
  769. }
  770. HRESULT
  771. CWsbDb::GetRecInfo(
  772. IN ULONG RecType,
  773. OUT COM_IDB_REC_INFO* pRecInfo
  774. )
  775. /*++
  776. Implements:
  777. IWsbDbPriv::GetRecInfo
  778. --*/
  779. {
  780. HRESULT hr = E_FAIL;
  781. WsbTraceIn(OLESTR("CWsbDb::GetRecInfo"), OLESTR(""));
  782. try {
  783. IMP_DB_INFO* pDbInfo;
  784. WsbAssert(0 != pRecInfo, E_POINTER);
  785. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  786. pDbInfo = (IMP_DB_INFO*)m_pImp;
  787. for (int i = 0; i < m_nRecTypes; i++) {
  788. if (m_RecInfo[i].Type == RecType) {
  789. pRecInfo->Type = m_RecInfo[i].Type;
  790. pRecInfo->EntityClassId = m_RecInfo[i].EntityClassId;
  791. pRecInfo->Flags = m_RecInfo[i].Flags;
  792. pRecInfo->MinSize = m_RecInfo[i].MinSize;
  793. pRecInfo->MaxSize = m_RecInfo[i].MaxSize;
  794. pRecInfo->nKeys = m_RecInfo[i].nKeys;
  795. hr = S_OK;
  796. break;
  797. }
  798. }
  799. } WsbCatch(hr);
  800. WsbTraceOut(OLESTR("CWsbDb::GetRecInfo"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  801. return(hr);
  802. }
  803. // GetJetIds - for a given record type, return the session ID,
  804. // the table ID, and the data column ID
  805. HRESULT CWsbDb::GetJetIds(JET_SESID SessionId, ULONG RecType,
  806. JET_TABLEID* pTableId, ULONG* pDataColId)
  807. {
  808. HRESULT hr = WSB_E_INVALID_DATA;
  809. WsbTraceIn(OLESTR("CWsbDb::GetJetIds"), OLESTR(""));
  810. try {
  811. JET_DBID DbId = 0;
  812. IMP_DB_INFO* pDbInfo;
  813. WsbAssert(0 != pTableId || 0 != pDataColId, E_POINTER);
  814. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  815. pDbInfo = (IMP_DB_INFO*)m_pImp;
  816. WsbTrace(OLESTR("CWsbDb::GetJetIds: this = %p, pDbInfo = %p\n"),
  817. this, pDbInfo);
  818. for (int index = 0; index < pDbInfo->nSessions; index++) {
  819. if (pDbInfo->SessionInfo[index].SessionId == SessionId) {
  820. DbId = pDbInfo->SessionInfo[index].DbId;
  821. break;
  822. }
  823. }
  824. WsbTrace(OLESTR("CWsbDb::GetJetIds: index = %d, DbId = %ld\n"), index, (LONG)DbId);
  825. WsbAffirm(index < pDbInfo->nSessions, E_FAIL);
  826. WsbAffirm(pDbInfo->SessionInfo[index].pTableInfo, WSB_E_NOT_INITIALIZED);
  827. for (int i = 0; i < m_nRecTypes; i++) {
  828. if (m_RecInfo[i].Type == RecType) {
  829. JET_ERR jstat;
  830. char table_name[20];
  831. IMP_TABLE_INFO* t_info = pDbInfo->SessionInfo[index].pTableInfo;
  832. WsbAffirmHr(jet_make_table_name(m_RecInfo[i].Type,
  833. table_name, 20));
  834. WsbTrace(OLESTR("CWsbDb::GetJetIds: t_info = %p, i = %d, table_name = <%hs>\n"),
  835. t_info, i, table_name);
  836. if (0 == t_info[i].TableId && 0 == t_info[i].ColId) {
  837. // Open the table for this record type
  838. WsbTrace(OLESTR("CWsbDb::GetJetIds: opening Jet table, SessionId = %lx, DbId = %ld, table_name = <%hs>, &TableId = %p\n"),
  839. (LONG)SessionId, (LONG)DbId, table_name, (&t_info[i].TableId));
  840. jstat = JetOpenTable(SessionId, DbId, table_name,
  841. NULL, 0, 0, &t_info[i].TableId);
  842. WsbTrace(OLESTR("CWsbDb::GetJetIds: TableId = %ld\n"),
  843. t_info[i].TableId);
  844. WsbAffirmHr(jet_error(jstat));
  845. // Get the column ID for the data column
  846. WsbAffirmHr(jet_get_column_id(SessionId, DbId, table_name,
  847. JET_DATA_COLUMN_NAME, &t_info[i].ColId));
  848. }
  849. if (0 != pTableId) {
  850. *pTableId = t_info[i].TableId;
  851. }
  852. if (0 != pDataColId) {
  853. *pDataColId = t_info[i].ColId;
  854. }
  855. hr = S_OK;
  856. break;
  857. }
  858. }
  859. } WsbCatch(hr);
  860. WsbTraceOut(OLESTR("CWsbDb::GetJetIds"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  861. return(hr);
  862. }
  863. // GetJetIndexInfo - for a given record type and key type, return information
  864. // about the key/index: the key size (in bytes), the column ID,
  865. // the index name
  866. HRESULT CWsbDb::GetJetIndexInfo(JET_SESID SessionId, ULONG RecType, ULONG KeyType,
  867. ULONG* pColId, OLECHAR** pName, ULONG bufferSize)
  868. {
  869. HRESULT hr = WSB_E_INVALID_DATA;
  870. WsbTraceIn(OLESTR("CWsbDb::GetJetIndexInfo"), OLESTR(""));
  871. try {
  872. JET_DBID DbId = 0;
  873. IMP_DB_INFO* pDbInfo;
  874. WsbAssert(0 != pColId || 0 != pName, E_POINTER);
  875. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  876. pDbInfo = (IMP_DB_INFO*)m_pImp;
  877. for (int index = 0; index < pDbInfo->nSessions; index++) {
  878. if (pDbInfo->SessionInfo[index].SessionId == SessionId) {
  879. DbId = pDbInfo->SessionInfo[index].DbId;
  880. break;
  881. }
  882. }
  883. WsbAffirm(index < pDbInfo->nSessions, E_FAIL);
  884. for (int i = 0; i < m_nRecTypes; i++) {
  885. if (m_RecInfo[i].Type == RecType) {
  886. char index_name[20];
  887. char table_name[20];
  888. WsbAffirmHr(jet_make_table_name(RecType, table_name, 20));
  889. if (0 == KeyType) {
  890. if (0 != pName) {
  891. WsbAffirm(bufferSize > strlen(JET_SEQNUM_COLUMN_NAME), E_FAIL);
  892. WsbAffirm(0 < mbstowcs(*pName, JET_SEQNUM_COLUMN_NAME,
  893. strlen(JET_SEQNUM_COLUMN_NAME) + 1), E_FAIL);
  894. }
  895. if (0 != pColId) {
  896. WsbAffirmHr(jet_get_column_id(SessionId, DbId, table_name,
  897. JET_SEQNUM_COLUMN_NAME, pColId));
  898. }
  899. hr = S_OK;
  900. } else {
  901. // Search for the given key type
  902. for (int j = 0; j < m_RecInfo[i].nKeys; j++) {
  903. if (m_RecInfo[i].Key[j].Type == KeyType) {
  904. WsbAffirmHr(jet_make_index_name(KeyType, index_name, 20));
  905. if (0 != pName) {
  906. WsbAffirm(bufferSize > strlen(index_name), E_FAIL);
  907. WsbAffirm(0 < mbstowcs(*pName, index_name,
  908. strlen(index_name) + 1), E_FAIL);
  909. }
  910. if (0 != pColId) {
  911. WsbAffirmHr(jet_get_column_id(SessionId, DbId, table_name,
  912. index_name, pColId));
  913. }
  914. hr = S_OK;
  915. break;
  916. }
  917. }
  918. }
  919. break;
  920. }
  921. }
  922. } WsbCatch(hr);
  923. WsbTraceOut(OLESTR("CWsbDb::GetJetIndexInfo"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  924. return(hr);
  925. }
  926. HRESULT
  927. CWsbDb::FinalConstruct(
  928. void
  929. )
  930. /*++
  931. Implements:
  932. CComObjectRoot::FinalConstruct
  933. --*/
  934. {
  935. HRESULT hr = S_OK;
  936. WsbTraceIn(OLESTR("CWsbDb::FinalConstruct"), OLESTR("") );
  937. try {
  938. IMP_DB_INFO* pDbInfo;
  939. WsbAffirmHr(CWsbPersistable::FinalConstruct());
  940. m_nRecTypes = 0;
  941. m_version = 0;
  942. m_pImp = NULL;
  943. m_RecInfo = NULL;
  944. m_SessionIndex = 0;
  945. // Allocate space for DB info & set
  946. pDbInfo = (IMP_DB_INFO*)WsbAlloc(sizeof(IMP_DB_INFO));
  947. m_pImp = pDbInfo;
  948. WsbAffirm(pDbInfo, E_OUTOFMEMORY);
  949. ZeroMemory(pDbInfo, sizeof(IMP_DB_INFO));
  950. pDbInfo->IsLoaded = FALSE;
  951. pDbInfo->OpenCount = 0;
  952. pDbInfo->nSessions = 0;
  953. pDbInfo->SessionInfo = NULL;
  954. } WsbCatch(hr);
  955. WsbTraceOut(OLESTR("CWsbDb::FinalConstruct"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  956. return(hr);
  957. }
  958. void
  959. CWsbDb::FinalRelease(
  960. void
  961. )
  962. /*++
  963. Implements:
  964. CComObjectRoot::FinalRelease
  965. --*/
  966. {
  967. HRESULT hr = S_OK;
  968. WsbTraceIn(OLESTR("CWsbDb::FinalRelease"), OLESTR(""));
  969. try {
  970. if (m_pImp) {
  971. int i;
  972. IMP_DB_INFO* pDbInfo;
  973. pDbInfo = (IMP_DB_INFO*)m_pImp;
  974. if (pDbInfo->RecInfo) {
  975. for (i = 0; i < m_nRecTypes; i++) {
  976. if (pDbInfo->RecInfo[i].Key) {
  977. WsbFree(pDbInfo->RecInfo[i].Key);
  978. }
  979. }
  980. WsbFree(pDbInfo->RecInfo);
  981. }
  982. // Make sure Jet resources are released
  983. if (NULL != pDbInfo->SessionInfo) {
  984. IMP_SESSION_INFO* s_info = pDbInfo->SessionInfo;
  985. for (i = 0; i < pDbInfo->nSessions; i++) {
  986. if (0 != s_info[i].SessionId && 0 != s_info[i].DbId) {
  987. JET_ERR jstat;
  988. jstat = JetCloseDatabase(s_info[i].SessionId,
  989. s_info[i].DbId, 0);
  990. WsbTrace(OLESTR("CWsbDb::FinalRelease: JetCloseDatabase[%d] = %ld\n"),
  991. i, (LONG)jstat);
  992. }
  993. if (s_info[i].pTableInfo) {
  994. WsbFree(s_info[i].pTableInfo);
  995. s_info[i].pTableInfo = NULL;
  996. }
  997. s_info[i].SessionId = 0;
  998. s_info[i].DbId = 0;
  999. }
  1000. WsbFree(pDbInfo->SessionInfo);
  1001. pDbInfo->SessionInfo = NULL;
  1002. }
  1003. pDbInfo->nSessions = 0;
  1004. WsbFree(pDbInfo);
  1005. m_pImp = NULL;
  1006. }
  1007. if (m_RecInfo) {
  1008. for (int i = 0; i < m_nRecTypes; i++) {
  1009. if (m_RecInfo[i].Key) {
  1010. WsbFree(m_RecInfo[i].Key);
  1011. }
  1012. }
  1013. WsbFree(m_RecInfo);
  1014. m_RecInfo = NULL;
  1015. }
  1016. CWsbPersistable::FinalRelease();
  1017. } WsbCatch(hr);
  1018. WsbTraceOut(OLESTR("CWsbDb::FinalRelease"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  1019. }
  1020. HRESULT
  1021. CWsbDb::GetClassID(
  1022. OUT CLSID* pClsid
  1023. )
  1024. /*++
  1025. Implements:
  1026. IPersist::GetClassID().
  1027. --*/
  1028. {
  1029. HRESULT hr = S_OK;
  1030. WsbTraceIn(OLESTR("CWsbDb::GetClassID"), OLESTR(""));
  1031. try {
  1032. WsbAssert(0 != pClsid, E_POINTER);
  1033. *pClsid = CLSID_CWsbDb;
  1034. } WsbCatch(hr);
  1035. WsbTraceOut(OLESTR("CWsbDb::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
  1036. return(hr);
  1037. }
  1038. HRESULT
  1039. CWsbDb::Load(
  1040. IN IStream* pStream
  1041. )
  1042. /*++
  1043. Implements:
  1044. IPersistStream::Load().
  1045. --*/
  1046. {
  1047. HRESULT hr = S_OK;
  1048. OLECHAR* name = NULL;
  1049. WsbTraceIn(OLESTR("CWsbDb::Load"), OLESTR(""));
  1050. try {
  1051. ULONG Bytes;
  1052. ULONG len = 0;
  1053. IMP_DB_INFO* pDbInfo;
  1054. FILE_DB_INFO db_file_block; // Used to move info to/from file
  1055. CComQIPtr<IWsbDb, &IID_IWsbDb> pIWsbDb = (IWsbDbPriv*)this;
  1056. WsbAssert(0 != pStream, E_POINTER);
  1057. WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED);
  1058. pDbInfo = (IMP_DB_INFO*)m_pImp;
  1059. // Don't allow loading into an already open DB
  1060. WsbAffirm(pDbInfo->OpenCount == 0, WSB_E_INVALID_DATA);
  1061. // Read the DB file name
  1062. WsbAffirmHr(WsbLoadFromStream(pStream, &name, 0));
  1063. if (name) {
  1064. len = wcslen(name);
  1065. }
  1066. // If the DB name is empty, there is no more info
  1067. if (0 < len) {
  1068. // Alloc space and read DB info
  1069. WsbAffirmHr(pStream->Read((void*)&db_file_block, sizeof(FILE_DB_INFO), &Bytes));
  1070. WsbAffirm(Bytes == sizeof(FILE_DB_INFO), WSB_E_STREAM_ERROR);
  1071. // Check DB version for match
  1072. WsbAffirm(db_file_block.version == m_version, WSB_E_IDB_WRONG_VERSION);
  1073. // Locate the DB
  1074. WsbAffirmHr(db_info_from_file_block(&db_file_block));
  1075. hr = Locate(name);
  1076. if (S_OK != hr) {
  1077. if (pDbInfo->RecInfo) {
  1078. WsbFree(pDbInfo->RecInfo);
  1079. pDbInfo->RecInfo = NULL;
  1080. }
  1081. }
  1082. } else {
  1083. hr = S_FALSE;
  1084. }
  1085. } WsbCatch(hr);
  1086. WsbFree(name);
  1087. WsbTraceOut(OLESTR("CWsbDb::Load"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  1088. return(hr);
  1089. }
  1090. HRESULT
  1091. CWsbDb::Save(
  1092. IN IStream* pStream,
  1093. IN BOOL clearDirty
  1094. )
  1095. /*++
  1096. Implements:
  1097. IPersistStream::Save().
  1098. --*/
  1099. {
  1100. HRESULT hr = S_OK;
  1101. WsbTraceIn(OLESTR("CWsbDb::Save"), OLESTR(""));
  1102. try {
  1103. ULONG Bytes;
  1104. ULONG len = 0;
  1105. FILE_DB_INFO db_file_block; // Used to move info to/from file
  1106. WsbAssert(0 != pStream, E_POINTER);
  1107. WsbAssert(m_pImp, WSB_E_NOT_INITIALIZED);
  1108. // Save the DB name
  1109. WsbAffirmHr(WsbSaveToStream(pStream, m_path));
  1110. WsbAffirmHr(m_path.GetLen(&len));
  1111. // If the name is empty, none of the other information is likely
  1112. // to be useful
  1113. if (0 < len) {
  1114. // Write some DB info
  1115. WsbAffirm(m_nRecTypes, WSB_E_NOT_INITIALIZED);
  1116. WsbAffirmHr(db_info_to_file_block(&db_file_block));
  1117. WsbAffirmHr(pStream->Write((void*)&db_file_block, sizeof(FILE_DB_INFO), &Bytes));
  1118. WsbAffirm(Bytes == sizeof(FILE_DB_INFO), WSB_E_STREAM_ERROR);
  1119. }
  1120. if (clearDirty) {
  1121. SetIsDirty(FALSE);
  1122. }
  1123. } WsbCatch(hr);
  1124. WsbTraceOut(OLESTR("CWsbDb::Save"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  1125. return(hr);
  1126. }
  1127. //
  1128. // Private functions
  1129. //
  1130. // db_info_from_file_block - copy data from DB info file block
  1131. HRESULT
  1132. CWsbDb::db_info_from_file_block(void* block)
  1133. {
  1134. HRESULT hr = S_OK;
  1135. try {
  1136. IMP_DB_INFO* pDbInfo;
  1137. ULONG Size;
  1138. FILE_DB_INFO *pDbFileBlock = (FILE_DB_INFO*)block;
  1139. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  1140. pDbInfo = (IMP_DB_INFO*)m_pImp;
  1141. WsbAssert(0 != pDbFileBlock, E_POINTER);
  1142. m_version = pDbFileBlock->version;
  1143. m_nRecTypes = pDbFileBlock->nRecTypes;
  1144. // Allocate record arrays
  1145. if (NULL == m_RecInfo) {
  1146. Size = m_nRecTypes * sizeof(IDB_REC_INFO);
  1147. m_RecInfo = (IDB_REC_INFO*)WsbAlloc(Size);
  1148. WsbAffirm(m_RecInfo, E_OUTOFMEMORY);
  1149. ZeroMemory(m_RecInfo, Size);
  1150. }
  1151. if (NULL == pDbInfo->RecInfo) {
  1152. Size = m_nRecTypes * sizeof(IMP_REC_INFO);
  1153. pDbInfo->RecInfo = (IMP_REC_INFO*)WsbAlloc(Size);
  1154. WsbAffirm(pDbInfo->RecInfo, E_OUTOFMEMORY);
  1155. ZeroMemory(pDbInfo->RecInfo, Size);
  1156. }
  1157. } WsbCatch(hr);
  1158. return(hr);
  1159. }
  1160. // db_info_to_file_block - copy data to DB info file block
  1161. HRESULT
  1162. CWsbDb::db_info_to_file_block(void* block)
  1163. {
  1164. HRESULT hr = S_OK;
  1165. try {
  1166. FILE_DB_INFO *pDbFileBlock = (FILE_DB_INFO*)block;
  1167. WsbAssert (0 != pDbFileBlock, E_POINTER);
  1168. pDbFileBlock->version = m_version;
  1169. pDbFileBlock->nRecTypes = m_nRecTypes;
  1170. } WsbCatch(hr);
  1171. return hr;
  1172. }
  1173. // rec_info_from_file_block - copy record data from rec info file block
  1174. HRESULT
  1175. CWsbDb::rec_info_from_file_block(int index, void* block)
  1176. {
  1177. HRESULT hr = S_OK;
  1178. try {
  1179. IMP_DB_INFO* pDbInfo;
  1180. ULONG Size;
  1181. FILE_REC_INFO *pRecFileBlock = (FILE_REC_INFO*)block;
  1182. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  1183. pDbInfo = (IMP_DB_INFO*)m_pImp;
  1184. WsbAssert (0 != pRecFileBlock, E_POINTER);
  1185. m_RecInfo[index].Type = pRecFileBlock->Type;
  1186. m_RecInfo[index].EntityClassId = pRecFileBlock->EntityClassId;
  1187. m_RecInfo[index].Flags = pRecFileBlock->Flags;
  1188. m_RecInfo[index].MinSize = pRecFileBlock->MinSize;
  1189. m_RecInfo[index].MaxSize = pRecFileBlock->MaxSize;
  1190. m_RecInfo[index].nKeys = pRecFileBlock->nKeys;
  1191. // Allocate Key arrays
  1192. if (NULL == m_RecInfo[index].Key) {
  1193. Size = m_RecInfo[index].nKeys * sizeof(IDB_KEY_INFO);
  1194. m_RecInfo[index].Key = (IDB_KEY_INFO*)WsbAlloc(Size);
  1195. WsbAffirm(m_RecInfo[index].Key, E_OUTOFMEMORY);
  1196. ZeroMemory(m_RecInfo[index].Key, Size);
  1197. }
  1198. if (NULL == pDbInfo->RecInfo[index].Key) {
  1199. Size = m_RecInfo[index].nKeys * sizeof(IMP_KEY_INFO);
  1200. pDbInfo->RecInfo[index].Key = (IMP_KEY_INFO*)WsbAlloc(Size);
  1201. WsbAffirm(pDbInfo->RecInfo[index].Key, E_OUTOFMEMORY);
  1202. ZeroMemory(pDbInfo->RecInfo[index].Key, Size);
  1203. }
  1204. for (int j = 0; j < pRecFileBlock->nKeys; j++) {
  1205. m_RecInfo[index].Key[j].Type = pRecFileBlock->Key[j].Type;
  1206. m_RecInfo[index].Key[j].Size = pRecFileBlock->Key[j].Size;
  1207. m_RecInfo[index].Key[j].Flags = pRecFileBlock->Key[j].Flags;
  1208. }
  1209. } WsbCatch(hr);
  1210. return(hr);
  1211. }
  1212. // rec_info_to_file_block - copy record data to rec info file block
  1213. HRESULT
  1214. CWsbDb::rec_info_to_file_block(int index, void* block)
  1215. {
  1216. HRESULT hr = S_OK;
  1217. try {
  1218. FILE_REC_INFO *pRecFileBlock = (FILE_REC_INFO*)block;
  1219. WsbAssert (0 != pRecFileBlock, E_POINTER);
  1220. // pRecFileBlock->SeqNum = m_RecInfo[index].SeqNum;
  1221. pRecFileBlock->Type = m_RecInfo[index].Type;
  1222. pRecFileBlock->EntityClassId = m_RecInfo[index].EntityClassId;
  1223. pRecFileBlock->Flags = m_RecInfo[index].Flags;
  1224. pRecFileBlock->MinSize = m_RecInfo[index].MinSize;
  1225. pRecFileBlock->MaxSize = m_RecInfo[index].MaxSize;
  1226. pRecFileBlock->nKeys = m_RecInfo[index].nKeys;
  1227. for (int j = 0; j < pRecFileBlock->nKeys; j++) {
  1228. pRecFileBlock->Key[j].Type = m_RecInfo[index].Key[j].Type;
  1229. pRecFileBlock->Key[j].Size = m_RecInfo[index].Key[j].Size;
  1230. pRecFileBlock->Key[j].Flags = m_RecInfo[index].Key[j].Flags;
  1231. }
  1232. } WsbCatch(hr);
  1233. return hr;
  1234. }
  1235. // session_current_index - find the index into the session info array.
  1236. // Sets m_SessionIndex if it's OK
  1237. HRESULT
  1238. CWsbDb::session_current_index(IWsbDbSession* pSession)
  1239. {
  1240. HRESULT hr = WSB_E_INVALID_DATA;
  1241. IMP_DB_INFO* pDbInfo;
  1242. CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = pSession;
  1243. WsbTraceIn(OLESTR("CWsbDB::session_current_index"), OLESTR(""));
  1244. pDbInfo = (IMP_DB_INFO*)m_pImp;
  1245. if (NULL != pDbInfo && NULL != pDbInfo->SessionInfo && pSessionPriv) {
  1246. JET_SESID SessionId;
  1247. if (S_OK == pSessionPriv->GetJetId(&SessionId)) {
  1248. for (int index = 0; index < pDbInfo->nSessions; index++) {
  1249. if (pDbInfo->SessionInfo[index].SessionId == SessionId) {
  1250. hr = S_OK;
  1251. m_SessionIndex = index;
  1252. break;
  1253. }
  1254. }
  1255. }
  1256. }
  1257. WsbTraceOut(OLESTR("CWsbDB::session_current_index"), OLESTR("sessionID[%ld] = %lx"),
  1258. m_SessionIndex, pDbInfo->SessionInfo[m_SessionIndex].SessionId);
  1259. return(hr);
  1260. }
  1261. // jet_init - make sure this IDB object is initialized for JET
  1262. HRESULT
  1263. CWsbDb::jet_init(void)
  1264. {
  1265. HRESULT hr = S_OK;
  1266. WsbTraceIn(OLESTR("CWsbDb::jet_init"), OLESTR(""));
  1267. try {
  1268. IMP_DB_INFO* pDbInfo;
  1269. pDbInfo = (IMP_DB_INFO*)m_pImp;
  1270. WsbTrace(OLESTR("CWsbDB::jet_init, nSessions = %d\n"),
  1271. (int)pDbInfo->nSessions);
  1272. if (0 == pDbInfo->nSessions) {
  1273. ULONG memSize;
  1274. // Allocate the thread info array
  1275. WsbAffirm(m_pWsbDbSys, E_FAIL);
  1276. memSize = SESSION_INFO_INITIAL_SIZE * sizeof(IMP_SESSION_INFO);
  1277. pDbInfo->SessionInfo = (IMP_SESSION_INFO*)WsbAlloc(memSize);
  1278. WsbAffirm(pDbInfo->SessionInfo, E_OUTOFMEMORY);
  1279. pDbInfo->nSessions = SESSION_INFO_INITIAL_SIZE;
  1280. ZeroMemory(pDbInfo->SessionInfo, memSize);
  1281. WsbTrace(OLESTR("CWsbDB::jet_init, SessionInfo(%ld bytes) allocated & zeroed\n"),
  1282. memSize);
  1283. // Begin a JET session for the IDB
  1284. m_SessionIndex = 0;
  1285. JET_SESID sid;
  1286. CComPtr<IWsbDbSession> pSession;
  1287. WsbAffirmHr(m_pWsbDbSys->GetGlobalSession(&pSession));
  1288. CComQIPtr<IWsbDbSessionPriv, &IID_IWsbDbSessionPriv> pSessionPriv = pSession;
  1289. WsbAffirmPointer(pSessionPriv);
  1290. WsbAffirmHr(pSessionPriv->GetJetId(&sid));
  1291. pDbInfo->SessionInfo[m_SessionIndex].SessionId = sid;
  1292. WsbTrace(OLESTR("CWsbDB::jet_init, SessionId[0] = %lx\n"),
  1293. pDbInfo->SessionInfo[m_SessionIndex].SessionId);
  1294. }
  1295. } WsbCatch(hr);
  1296. WsbTraceOut(OLESTR("CWsbDb::jet_init"), OLESTR("hr =<%ls>"), WsbHrAsString(hr));
  1297. return(hr);
  1298. }
  1299. // jet_load_info - load DB info from database
  1300. HRESULT
  1301. CWsbDb::jet_load_info(void)
  1302. {
  1303. HRESULT hr = S_OK;
  1304. IMP_DB_INFO* pDbInfo = NULL;
  1305. JET_TABLEID table_id = 0;
  1306. JET_ERR jstat;
  1307. WsbTraceIn(OLESTR("CWsbDb::jet_load_info"), OLESTR(""));
  1308. try {
  1309. JET_COLUMNID col_id_data;
  1310. ULONG size;
  1311. FILE_DB_INFO db_file_block; // Used to move info to/from file
  1312. FILE_REC_INFO rec_file_block; // Used to move record info
  1313. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  1314. pDbInfo = (IMP_DB_INFO*)m_pImp;
  1315. // Open the info table
  1316. jstat = JetOpenTable(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME,
  1317. NULL, 0, 0, &table_id);
  1318. if (jstat != JET_errSuccess) {
  1319. table_id = 0;
  1320. }
  1321. WsbTrace(OLESTR("CWsbDb::jet_load_info: open TableId = %ld\n"),
  1322. table_id);
  1323. WsbAffirmHr(jet_error(jstat));
  1324. WsbAffirmHr(jet_get_column_id(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME,
  1325. JET_DATA_COLUMN_NAME, &col_id_data));
  1326. jstat = JetSetCurrentIndex(JET_CURRENT_SESSION, table_id, NULL);
  1327. WsbAffirmHr(jet_error(jstat));
  1328. // Get the DB info and check for match
  1329. jstat = JetRetrieveColumn(JET_CURRENT_SESSION, table_id, col_id_data,
  1330. &db_file_block, sizeof(FILE_DB_INFO), &size, 0, NULL);
  1331. WsbAffirmHr(jet_error(jstat));
  1332. WsbAffirm(db_file_block.nRecTypes > 0, WSB_E_INVALID_DATA);
  1333. WsbAffirm(db_file_block.version == m_version, WSB_E_IDB_WRONG_VERSION);
  1334. WsbAffirmHr(db_info_from_file_block(&db_file_block));
  1335. // Get the record/key info
  1336. for (int i = 0; i < m_nRecTypes; i++) {
  1337. jstat = JetMove(JET_CURRENT_SESSION, table_id, JET_MoveNext, 0);
  1338. WsbAffirmHr(jet_error(jstat));
  1339. jstat = JetRetrieveColumn(JET_CURRENT_SESSION, table_id, col_id_data,
  1340. &rec_file_block, sizeof(FILE_REC_INFO), &size, 0, NULL);
  1341. WsbAffirmHr(jet_error(jstat));
  1342. WsbAffirmHr(rec_info_from_file_block(i, &rec_file_block));
  1343. }
  1344. } WsbCatch(hr);
  1345. if (table_id) {
  1346. jstat = JetCloseTable(JET_CURRENT_SESSION, table_id);
  1347. WsbTrace(OLESTR("CWsbDb::jet_load_info: close TableId = %ld, jstat = %ld\n"),
  1348. table_id, jstat);
  1349. }
  1350. WsbTraceOut(OLESTR("CWsbDb::jet_load_info"), OLESTR("hr =<%ls>"),
  1351. WsbHrAsString(hr));
  1352. return(hr);
  1353. }
  1354. // jet_make_index_name - convert key type to index name
  1355. HRESULT
  1356. CWsbDb::jet_make_index_name(ULONG key_type, char* pName, ULONG bufsize)
  1357. {
  1358. HRESULT hr = E_FAIL;
  1359. char lbuf[20];
  1360. if (pName != NULL) {
  1361. sprintf(lbuf, "%ld", key_type);
  1362. if (bufsize > strlen(lbuf)) {
  1363. strcpy(pName, lbuf);
  1364. hr = S_OK;
  1365. }
  1366. }
  1367. return(hr);
  1368. }
  1369. // jet_make_table_name - convert record type to table name
  1370. HRESULT
  1371. CWsbDb::jet_make_table_name(ULONG rec_type, char* pName, ULONG bufsize)
  1372. {
  1373. HRESULT hr = E_FAIL;
  1374. char lbuf[20];
  1375. if (pName != NULL) {
  1376. sprintf(lbuf, "%ld", rec_type);
  1377. if (bufsize > strlen(lbuf)) {
  1378. strcpy(pName, lbuf);
  1379. hr = S_OK;
  1380. }
  1381. }
  1382. return(hr);
  1383. }
  1384. // jet_save_info - save DB info to database
  1385. HRESULT
  1386. CWsbDb::jet_save_info()
  1387. {
  1388. HRESULT hr = S_OK;
  1389. IMP_DB_INFO* pDbInfo = NULL;
  1390. JET_TABLEID table_id = 0;
  1391. JET_ERR jstat;
  1392. try {
  1393. JET_COLUMNID col_id_data;
  1394. JET_COLUMNID col_id_index;
  1395. SHORT data_number;
  1396. FILE_DB_INFO db_file_block; // Used to move info to/from file
  1397. FILE_REC_INFO rec_file_block; // Used to move record info
  1398. WsbAffirm(m_pImp, WSB_E_NOT_INITIALIZED);
  1399. pDbInfo = (IMP_DB_INFO*)m_pImp;
  1400. // Open the table
  1401. jstat = JetOpenTable(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME,
  1402. NULL, 0, 0, &table_id);
  1403. WsbTrace(OLESTR("CWsbDb::jet_save_info: open TableId = %ld\n"),
  1404. table_id);
  1405. WsbAffirmHr(jet_error(jstat));
  1406. WsbAffirmHr(jet_get_column_id(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME,
  1407. JET_INDEX_COLUMN_NAME, &col_id_index));
  1408. WsbAffirmHr(jet_get_column_id(JET_CURRENT_SESSION, JET_CURRENT_DB, JET_INFO_TABLE_NAME,
  1409. JET_DATA_COLUMN_NAME, &col_id_data));
  1410. // Put the DB info
  1411. jstat = JetPrepareUpdate(JET_CURRENT_SESSION, table_id, JET_prepInsert);
  1412. WsbAffirmHr(jet_error(jstat));
  1413. WsbAffirmHr(db_info_to_file_block(&db_file_block));
  1414. data_number = 0;
  1415. jstat = JetSetColumn(JET_CURRENT_SESSION, table_id, col_id_index, &data_number,
  1416. sizeof(data_number), 0, NULL);
  1417. WsbAffirmHr(jet_error(jstat));
  1418. jstat = JetSetColumn(JET_CURRENT_SESSION, table_id, col_id_data, &db_file_block,
  1419. sizeof(FILE_DB_INFO), 0, NULL);
  1420. WsbAffirmHr(jet_error(jstat));
  1421. jstat = JetUpdate(JET_CURRENT_SESSION, table_id, NULL, 0, NULL);
  1422. WsbAffirmHr(jet_error(jstat));
  1423. // Put the record/key info
  1424. for (int i = 0; i < m_nRecTypes; i++) {
  1425. jstat = JetPrepareUpdate(JET_CURRENT_SESSION, table_id, JET_prepInsert);
  1426. WsbAffirmHr(jet_error(jstat));
  1427. WsbAffirmHr(rec_info_to_file_block(i, &rec_file_block));
  1428. data_number = (SHORT) ( i + 1 );
  1429. jstat = JetSetColumn(JET_CURRENT_SESSION, table_id, col_id_index, &data_number,
  1430. sizeof(data_number), 0, NULL);
  1431. WsbAffirmHr(jet_error(jstat));
  1432. jstat = JetSetColumn(JET_CURRENT_SESSION, table_id, col_id_data, &rec_file_block,
  1433. sizeof(FILE_REC_INFO), 0, NULL);
  1434. WsbAffirmHr(jet_error(jstat));
  1435. jstat = JetUpdate(JET_CURRENT_SESSION, table_id, NULL, 0, NULL);
  1436. WsbAffirmHr(jet_error(jstat));
  1437. }
  1438. } WsbCatch(hr);
  1439. if (table_id) {
  1440. jstat = JetCloseTable(JET_CURRENT_SESSION, table_id);
  1441. WsbTrace(OLESTR("CWsbDb::jet_save_info: close TableId = %ld, jstat = %ld\n"),
  1442. table_id, jstat);
  1443. }
  1444. return(hr);
  1445. }
  1446. // Local functions
  1447. // jet_get_column_id - convert a column name to a column ID
  1448. static HRESULT jet_get_column_id(JET_SESID jet_session, JET_DBID DbId,
  1449. char* pTableName, char* pColumnName, JET_COLUMNID* pColId)
  1450. {
  1451. HRESULT hr = S_OK;
  1452. WsbTraceIn(OLESTR("jet_get_column_id"), OLESTR("SessId = %lx, DbId = %lx"),
  1453. (ULONG)jet_session, (ULONG)DbId);
  1454. try {
  1455. JET_COLUMNBASE col_base;
  1456. JET_ERR jstat;
  1457. WsbAssert(NULL != pColId, E_POINTER);
  1458. jstat = JetGetColumnInfo(jet_session, DbId, pTableName, pColumnName,
  1459. &col_base, sizeof(col_base), JET_ColInfoBase);
  1460. WsbAssertHr(jet_error(jstat));
  1461. *pColId = col_base.columnid;
  1462. } WsbCatch(hr);
  1463. WsbTraceOut(OLESTR("jet_get_column_id"), OLESTR("col_id = %ld"),
  1464. (LONG)*pColId);
  1465. return(hr);
  1466. }