Source code of Windows XP (NT5)
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.

2047 lines
50 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. database.cpp
  5. Abstract:
  6. SIS Groveler Jet-Blue database front-end
  7. Authors:
  8. Cedric Krumbein, 1998
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include "all.hxx"
  14. /*****************************************************************************/
  15. /*************** SGDatabase class static value initializations ***************/
  16. /*****************************************************************************/
  17. DWORD SGDatabase::numInstances = 0;
  18. JET_INSTANCE SGDatabase::instance = 0;
  19. BOOL SGDatabase::jetInitialized = FALSE;
  20. TCHAR * SGDatabase::logDir = NULL;
  21. /*****************************************************************************/
  22. /****************** SGDatabase class private static methods ******************/
  23. /*****************************************************************************/
  24. BOOL SGDatabase::set_log_drive(const _TCHAR *drive_name)
  25. {
  26. int drive_name_len = _tcslen(drive_name);
  27. int cs_dir_path_len = _tcslen(CS_DIR_PATH);
  28. ASSERT(NULL == logDir);
  29. logDir = new TCHAR[drive_name_len + cs_dir_path_len + 1 - 1];
  30. ASSERT(NULL != logDir);
  31. _tcsncpy(SGDatabase::logDir, drive_name, drive_name_len - 1);
  32. _tcscpy(&SGDatabase::logDir[drive_name_len-1], CS_DIR_PATH);
  33. return TRUE;
  34. }
  35. BOOL SGDatabase::InitializeEngine()
  36. {
  37. DWORD_PTR maxVerPages;
  38. DWORD_PTR minCacheSize;
  39. DWORD_PTR newCacheSize;
  40. DWORDLONG cacheSize;
  41. DWORD circularLog;
  42. MEMORYSTATUSEX memStatus;
  43. SYSTEM_INFO sysInfo;
  44. JET_ERR jetErr;
  45. ASSERT(!jetInitialized);
  46. ASSERT(logDir);
  47. if (!SetCurrentDirectory(logDir)) {
  48. DPRINTF((_T("SGDatabase::InitializeEngine: can't cd to \"%s\", %ld\n"), logDir, GetLastError()));
  49. return FALSE;
  50. }
  51. circularLog = 1;
  52. jetErr = JetSetSystemParameter(&instance, 0,
  53. JET_paramCircularLog, circularLog, NULL);
  54. if (jetErr != JET_errSuccess) {
  55. DPRINTF((_T("(2) JetSetSystemParameter: jetErr=%ld\n"), jetErr));
  56. return FALSE;
  57. }
  58. //
  59. // Set the maximum cache size used by the database engine to min(4% phys mem, 6M).
  60. //
  61. jetErr = JetGetSystemParameter(instance, 0,
  62. JET_paramCacheSizeMin, &minCacheSize, NULL, 0);
  63. if (jetErr != JET_errSuccess) {
  64. DPRINTF((_T("JetGetSystemParameter: jetErr=%ld\n"), jetErr));
  65. TerminateEngine();
  66. return FALSE;
  67. }
  68. memStatus.dwLength = sizeof memStatus;
  69. GlobalMemoryStatusEx(&memStatus); // get total physical memory
  70. GetSystemInfo(&sysInfo); // get page size
  71. cacheSize = memStatus.ullTotalPhys / 25; // 4%
  72. newCacheSize = (DWORD) min(cacheSize, MAX_DATABASE_CACHE_SIZE);
  73. newCacheSize = newCacheSize / sysInfo.dwPageSize;
  74. if (newCacheSize < minCacheSize)
  75. newCacheSize = minCacheSize;
  76. jetErr = JetSetSystemParameter(&instance, 0,
  77. JET_paramCacheSizeMax, newCacheSize, NULL);
  78. if (jetErr != JET_errSuccess) {
  79. DPRINTF((_T("(3) JetSetSystemParameter: jetErr=%ld\n"), jetErr));
  80. return FALSE;
  81. }
  82. //
  83. // Set Version Cache size
  84. //
  85. jetErr = JetGetSystemParameter(instance, 0,
  86. JET_paramMaxVerPages, &maxVerPages, NULL, 0);
  87. if (jetErr != JET_errSuccess) {
  88. DPRINTF((_T("(2) JetGetSystemParameter: jetErr=%ld\n"), jetErr));
  89. TerminateEngine();
  90. return FALSE;
  91. }
  92. if (maxVerPages >= MIN_VER_PAGES) {
  93. DPRINTF((_T("JetGetSystemParameter(instance=%lu): MaxVerPages=%lu\n"),
  94. instance, maxVerPages));
  95. } else {
  96. maxVerPages = MIN_VER_PAGES;
  97. jetErr = JetSetSystemParameter(&instance, 0,
  98. JET_paramMaxVerPages, maxVerPages, NULL);
  99. if (jetErr != JET_errSuccess) {
  100. DPRINTF((_T("(4) JetSetSystemParameter: jetErr=%ld\n"), jetErr));
  101. TerminateEngine();
  102. return FALSE;
  103. }
  104. DPRINTF((_T("JetSetSystemParameter(instance=%lu, MaxVerPages)=%lu\n"),
  105. instance, maxVerPages));
  106. }
  107. //
  108. // Initialize Jet
  109. //
  110. jetErr = JetInit(&instance);
  111. if (jetErr != JET_errSuccess) {
  112. DPRINTF((_T("JetInit: jetErr=%ld\n"), jetErr));
  113. return FALSE;
  114. }
  115. jetInitialized = TRUE;
  116. DPRINTF((_T("JetInit: instance=%lu\n"), instance));
  117. return TRUE;
  118. }
  119. /*****************************************************************************/
  120. BOOL SGDatabase::TerminateEngine()
  121. {
  122. JET_ERR jetErr;
  123. BOOL rc;
  124. ASSERT(jetInitialized);
  125. jetErr = JetTerm(instance);
  126. if (jetErr != JET_errSuccess) {
  127. DPRINTF((_T("JetTerm: jetErr=%ld\n"), jetErr));
  128. rc = FALSE;
  129. } else {
  130. rc = TRUE;
  131. // Delete no longer needed jet files.
  132. if (logDir) {
  133. WIN32_FIND_DATA findData;
  134. HANDLE fHandle;
  135. BOOL success;
  136. TFileName fName,
  137. delName;
  138. delName.assign(logDir);
  139. delName.append(_T("\\"));
  140. delName.append(DATABASE_DELETE_RES_FILE_NAME);
  141. fHandle = FindFirstFile(delName.name, &findData);
  142. if (fHandle != INVALID_HANDLE_VALUE) {
  143. do {
  144. if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  145. success = GetParentName(delName.name, &fName);
  146. ASSERT(success); // internal error if failed
  147. fName.append(_T("\\"));
  148. fName.append(findData.cFileName);
  149. if (!DeleteFile(fName.name)) {
  150. DPRINTF((_T("SGDatabase::Close: can't delete \"%s\", %d\n"), delName.name, GetLastError()));
  151. }
  152. }
  153. } while (FindNextFile(fHandle, &findData));
  154. success = FindClose(fHandle);
  155. ASSERT(success);
  156. fHandle = NULL;
  157. }
  158. }
  159. }
  160. jetInitialized = FALSE;
  161. DPRINTF((_T("JetTerm\n")));
  162. return rc;
  163. }
  164. /*****************************************************************************/
  165. /********************** SGDatabase class private methods *********************/
  166. /*****************************************************************************/
  167. BOOL SGDatabase::CreateTable(
  168. const CHAR *tblName,
  169. DWORD numColumns,
  170. ColumnSpec **columnSpecs,
  171. JET_COLUMNID *columnIDs,
  172. JET_TABLEID *tblID)
  173. {
  174. JET_COLUMNDEF columnDef;
  175. JET_COLUMNID colIDcount;
  176. JET_ERR jetErr;
  177. ColumnSpec *columnSpec;
  178. DWORD i, j;
  179. ASSERT(sesID != ~0);
  180. ASSERT(dbID != ~0);
  181. ASSERT(numColumns <= MAX_COLUMNS);
  182. jetErr = JetCreateTable(sesID, dbID, tblName,
  183. TABLE_PAGES, TABLE_DENSITY, tblID);
  184. if (jetErr != JET_errSuccess) {
  185. DPRINTF((_T("JetCreateTable: jetErr=%ld\n"), jetErr));
  186. return FALSE;
  187. }
  188. DPRINTF((_T("JetCreateTable: tblID=%lu colIDs={"), *tblID));
  189. columnDef.cbStruct = sizeof(JET_COLUMNDEF);
  190. columnDef.wCountry = COUNTRY_CODE;
  191. columnDef.langid = LANG_ID;
  192. columnDef.cp = CODE_PAGE;
  193. columnDef.wCollate = COLLATE;
  194. colIDcount = 1;
  195. for (i = 0; i < numColumns; i++) {
  196. columnSpec = columnSpecs[i];
  197. columnDef.columnid = colIDcount;
  198. columnDef.coltyp = columnSpec->coltyp;
  199. columnDef.cbMax = columnSpec->size;
  200. columnDef.grbit = columnSpec->grbit;
  201. jetErr = JetAddColumn(sesID, *tblID, columnSpec->name,
  202. &columnDef, NULL, 0, &columnIDs[i]);
  203. if (jetErr != JET_errSuccess) {
  204. DPRINTF((_T("\nJetAddColumn: jetErr=%ld\n"), jetErr));
  205. return FALSE;
  206. }
  207. DPRINTF((_T(" %lu"), columnIDs[i]));
  208. if (i+1 < numColumns && colIDcount == columnIDs[i]) {
  209. ColIDCollision:
  210. colIDcount++;
  211. for (j = 0; j < i; j++)
  212. if (colIDcount == columnIDs[j])
  213. goto ColIDCollision;
  214. }
  215. }
  216. DPRINTF((_T(" }\n")));
  217. return TRUE;
  218. }
  219. /*****************************************************************************/
  220. BOOL SGDatabase::CreateIndex(
  221. JET_TABLEID tblID,
  222. const CHAR *keyName,
  223. DWORD numKeys,
  224. ColumnSpec **keyColumnSpecs)
  225. {
  226. JET_ERR jetErr;
  227. CHAR indexStr[MAX_PATH];
  228. ColumnSpec *keyColumnSpec;
  229. DWORD indexStrLen,
  230. i;
  231. ASSERT(sesID != ~0);
  232. ASSERT(numKeys <= MAX_KEYS);
  233. indexStrLen = 0;
  234. for (i = 0; i < numKeys; i++) {
  235. keyColumnSpec = keyColumnSpecs[i];
  236. indexStr[indexStrLen++] = '+';
  237. strcpy(indexStr + indexStrLen, keyColumnSpec->name);
  238. indexStrLen += strlen(keyColumnSpec->name) + 1;
  239. }
  240. indexStr[indexStrLen++] = '\0';
  241. jetErr = JetCreateIndex(sesID, tblID, keyName, 0,
  242. indexStr, indexStrLen, TABLE_DENSITY);
  243. if (jetErr != JET_errSuccess) {
  244. DPRINTF((_T("JetCreateIndex: jetErr=%ld\n"), jetErr));
  245. return FALSE;
  246. }
  247. return TRUE;
  248. }
  249. /*****************************************************************************/
  250. BOOL SGDatabase::OpenTable(
  251. const CHAR *tblName,
  252. DWORD numColumns,
  253. ColumnSpec **columnSpecs,
  254. JET_COLUMNID *columnIDs,
  255. JET_TABLEID *tblID)
  256. {
  257. JET_COLUMNDEF columnDef;
  258. JET_ERR jetErr;
  259. ColumnSpec *columnSpec;
  260. DWORD i;
  261. ASSERT(sesID != ~0);
  262. ASSERT(dbID != ~0);
  263. ASSERT(numColumns <= MAX_COLUMNS);
  264. jetErr = JetOpenTable(sesID, dbID, tblName, NULL, 0, 0, tblID);
  265. if (jetErr != JET_errSuccess) {
  266. DPRINTF((_T("JetOpenTable: jetErr=%ld\n"), jetErr));
  267. return FALSE;
  268. }
  269. DPRINTF((_T("JetOpenTable: tblID=%lu colIDs={"), *tblID));
  270. for (i = 0; i < numColumns; i++) {
  271. columnSpec = columnSpecs[i];
  272. jetErr = JetGetTableColumnInfo(sesID, *tblID, columnSpec->name,
  273. &columnDef, sizeof(JET_COLUMNDEF), JET_ColInfo);
  274. if (jetErr != JET_errSuccess) {
  275. DPRINTF((_T("\nJetGetTableColumnInfo: jetErr=%ld\n"), jetErr));
  276. return FALSE;
  277. }
  278. columnIDs[i] = columnDef.columnid;
  279. DPRINTF((_T(" %lu"), columnIDs[i]));
  280. }
  281. DPRINTF((_T(" }\n")));
  282. return TRUE;
  283. }
  284. /*****************************************************************************/
  285. BOOL SGDatabase::CloseTable(JET_TABLEID tblID)
  286. {
  287. JET_ERR jetErr;
  288. ASSERT(sesID != ~0);
  289. ASSERT(tblID != ~0);
  290. jetErr = JetCloseTable(sesID, tblID);
  291. if (jetErr != JET_errSuccess) {
  292. DPRINTF((_T("JetCloseTable: jetErr=%ld\n"), jetErr));
  293. return FALSE;
  294. }
  295. return TRUE;
  296. }
  297. /*****************************************************************************/
  298. LONG SGDatabase::PositionCursor(
  299. JET_TABLEID tblID,
  300. const CHAR *keyName,
  301. const VOID *entry,
  302. DWORD numKeys,
  303. ColumnSpec **keyColumnSpecs) const
  304. {
  305. JET_COLTYP coltyp;
  306. JET_ERR jetErr;
  307. ColumnSpec *keyColumnSpec;
  308. const BYTE *dataPtr[MAX_KEYS];
  309. DWORD cbData[MAX_KEYS],
  310. i;
  311. ASSERT(sesID != ~0);
  312. ASSERT(numKeys <= MAX_KEYS);
  313. jetErr = JetSetCurrentIndex(sesID, tblID, keyName);
  314. if (jetErr != JET_errSuccess) {
  315. DPRINTF((_T("JetSetCurrentIndex: jetErr=%ld\n"), jetErr));
  316. return -1;
  317. }
  318. for (i = 0; i < numKeys; i++) {
  319. keyColumnSpec = keyColumnSpecs[i];
  320. coltyp = keyColumnSpec->coltyp;
  321. dataPtr[i] = (const BYTE *)entry + keyColumnSpec->offset;
  322. if (coltyp == JET_coltypBinary) {
  323. dataPtr[i] = *(BYTE **)dataPtr[i];
  324. ASSERT(dataPtr[i] != NULL);
  325. cbData[i] = (_tcslen((const TCHAR *)dataPtr[i]) + 1) * sizeof(TCHAR);
  326. } else
  327. cbData[i] = keyColumnSpec->size;
  328. jetErr = JetMakeKey(sesID, tblID, dataPtr[i], cbData[i],
  329. i == 0 ? JET_bitNewKey : 0);
  330. if (jetErr != JET_errSuccess) {
  331. DPRINTF((_T("JetMakeKey: jetErr=%ld\n"), jetErr));
  332. return -1;
  333. }
  334. }
  335. jetErr = JetSeek(sesID, tblID, JET_bitSeekEQ);
  336. if (jetErr != JET_errSuccess) {
  337. if (jetErr == JET_errRecordNotFound)
  338. return 0;
  339. DPRINTF((_T("JetSeek: jetErr=%ld\n"), jetErr));
  340. return -1;
  341. }
  342. for (i = 0; i < numKeys; i++) {
  343. jetErr = JetMakeKey(sesID, tblID, dataPtr[i], cbData[i],
  344. i == 0 ? JET_bitNewKey : 0);
  345. if (jetErr != JET_errSuccess) {
  346. DPRINTF((_T("JetMakeKey: jetErr=%ld\n"), jetErr));
  347. return -1;
  348. }
  349. }
  350. jetErr = JetSetIndexRange(sesID, tblID,
  351. JET_bitRangeUpperLimit | JET_bitRangeInclusive);
  352. if (jetErr != JET_errSuccess) {
  353. DPRINTF((_T("JetSetIndexRange: jetErr=%ld\n"), jetErr));
  354. return -1;
  355. }
  356. return 1;
  357. }
  358. /*****************************************************************************/
  359. LONG SGDatabase::PositionCursorFirst(
  360. JET_TABLEID tblID,
  361. const CHAR *keyName) const
  362. {
  363. JET_ERR jetErr;
  364. ASSERT(sesID != ~0);
  365. jetErr = JetSetCurrentIndex(sesID, tblID, keyName);
  366. if (jetErr != JET_errSuccess) {
  367. DPRINTF((_T("JetSetCurrentIndex: jetErr=%ld\n"), jetErr));
  368. return -1;
  369. }
  370. jetErr = JetMove(sesID, tblID, JET_MoveFirst, 0);
  371. if (jetErr != JET_errSuccess) {
  372. if (jetErr == JET_errNoCurrentRecord)
  373. return 0;
  374. DPRINTF((_T("JetMove: jetErr=%ld\n"), jetErr));
  375. return -1;
  376. }
  377. return 1;
  378. }
  379. /*****************************************************************************/
  380. LONG SGDatabase::PositionCursorNext(JET_TABLEID tblID) const
  381. {
  382. JET_ERR jetErr;
  383. ASSERT(sesID != ~0);
  384. jetErr = JetMove(sesID, tblID, JET_MoveNext, 0);
  385. if (jetErr != JET_errSuccess) {
  386. if (jetErr == JET_errNoCurrentRecord)
  387. return 0;
  388. DPRINTF((_T("JetMove: jetErr=%ld\n"), jetErr));
  389. return -1;
  390. }
  391. return 1;
  392. }
  393. /*****************************************************************************/
  394. LONG SGDatabase::PositionCursorLast(
  395. JET_TABLEID tblID,
  396. const CHAR *keyName) const
  397. {
  398. JET_ERR jetErr;
  399. ASSERT(sesID != ~0);
  400. jetErr = JetSetCurrentIndex(sesID, tblID, keyName);
  401. if (jetErr != JET_errSuccess) {
  402. DPRINTF((_T("JetSetCurrentIndex: jetErr=%ld\n"), jetErr));
  403. return -1;
  404. }
  405. jetErr = JetMove(sesID, tblID, JET_MoveLast, 0);
  406. if (jetErr != JET_errSuccess) {
  407. if (jetErr == JET_errNoCurrentRecord)
  408. return 0;
  409. DPRINTF((_T("JetMove: jetErr=%ld\n"), jetErr));
  410. return -1;
  411. }
  412. return 1;
  413. }
  414. /*****************************************************************************/
  415. BOOL SGDatabase::PutData(
  416. JET_TABLEID tblID,
  417. const VOID *entry,
  418. DWORD numColumns,
  419. ColumnSpec **columnSpecs,
  420. const JET_COLUMNID *columnIDs)
  421. {
  422. JET_COLTYP coltyp;
  423. JET_ERR jetErr;
  424. ColumnSpec *columnSpec;
  425. const BYTE *dataPtr;
  426. DWORD cbData,
  427. i;
  428. ASSERT(sesID != ~0);
  429. ASSERT(numColumns <= MAX_COLUMNS);
  430. jetErr = JetPrepareUpdate(sesID, tblID, JET_prepInsert);
  431. if (jetErr != JET_errSuccess) {
  432. DPRINTF((_T("JetPrepareUpdate: jetErr=%ld\n"), jetErr));
  433. return FALSE;
  434. }
  435. for (i = 0; i < numColumns; i++) {
  436. columnSpec = columnSpecs[i];
  437. coltyp = columnSpec->coltyp;
  438. if (columnSpec->grbit != JET_bitColumnAutoincrement) {
  439. dataPtr = (const BYTE *)entry + columnSpec->offset;
  440. if (coltyp == JET_coltypBinary
  441. || coltyp == JET_coltypLongBinary) {
  442. dataPtr = *(BYTE **)dataPtr;
  443. cbData = dataPtr != NULL
  444. ? (_tcslen((const TCHAR *)dataPtr) + 1) * sizeof(TCHAR)
  445. : 0;
  446. } else
  447. cbData = columnSpec->size;
  448. // May want to convert to JetSetColumns
  449. jetErr = JetSetColumn(sesID, tblID, columnIDs[i],
  450. dataPtr, cbData, 0, NULL);
  451. if (jetErr != JET_errSuccess) {
  452. DPRINTF((_T("JetSetColumn: jetErr=%ld\n"), jetErr));
  453. return FALSE;
  454. }
  455. }
  456. }
  457. jetErr = JetUpdate(sesID, tblID, NULL, 0, NULL);
  458. if (jetErr != JET_errSuccess) {
  459. DPRINTF((_T("JetUpdate: jetErr=%ld\n"), jetErr));
  460. return FALSE;
  461. }
  462. return TRUE;
  463. }
  464. /*****************************************************************************/
  465. BOOL SGDatabase::RetrieveData(
  466. JET_TABLEID tblID,
  467. VOID *entry,
  468. DWORD numColumns,
  469. ColumnSpec **columnSpecs,
  470. const JET_COLUMNID *columnIDs,
  471. DWORD includeMask) const
  472. {
  473. JET_COLTYP coltyp;
  474. JET_ERR jetErr;
  475. ColumnSpec *columnSpec;
  476. BYTE *dataPtr;
  477. DWORD cbData,
  478. cbActual,
  479. i;
  480. BOOL varCol;
  481. ASSERT(sesID != ~0);
  482. ASSERT(numColumns <= MAX_COLUMNS);
  483. // May want to convert to JetRetrieveColumns
  484. for (i = 0; i < numColumns; i++)
  485. if ((includeMask & (1U << i)) != 0) {
  486. columnSpec = columnSpecs[i];
  487. coltyp = columnSpec->coltyp;
  488. varCol = coltyp == JET_coltypBinary
  489. || coltyp == JET_coltypLongBinary;
  490. dataPtr = (BYTE *)entry + columnSpec->offset;
  491. if (varCol)
  492. dataPtr = *(BYTE **)dataPtr;
  493. if (dataPtr != NULL) {
  494. jetErr = JetRetrieveColumn(sesID, tblID, columnIDs[i],
  495. dataPtr, columnSpec->size, &cbActual, 0, NULL);
  496. if (jetErr == JET_errSuccess)
  497. cbData = varCol
  498. ? (_tcslen((TCHAR *)dataPtr) + 1) * sizeof(TCHAR)
  499. : columnSpec->size;
  500. else if (varCol && jetErr == JET_wrnColumnNull) {
  501. *(TCHAR *)dataPtr = _T('\0');
  502. cbData = 0;
  503. } else {
  504. DPRINTF((_T("JetRetrieveColumn: jetErr=%ld\n"), jetErr));
  505. return FALSE;
  506. }
  507. if (cbActual != cbData) {
  508. DPRINTF((_T("JetRetrieveColumn: cbActual=%lu!=%lu\n"),
  509. cbActual, cbData));
  510. return FALSE;
  511. }
  512. }
  513. }
  514. return TRUE;
  515. }
  516. /*****************************************************************************/
  517. LONG SGDatabase::Delete(JET_TABLEID tblID)
  518. {
  519. JET_ERR jetErr;
  520. LONG count,
  521. status;
  522. count = 0;
  523. ASSERT(sesID != ~0);
  524. while (TRUE) {
  525. jetErr = JetDelete(sesID, tblID);
  526. if (jetErr != JET_errSuccess) {
  527. DPRINTF((_T("JetDelete: jetErr=%ld\n"), jetErr));
  528. return -1;
  529. }
  530. count++;
  531. status = PositionCursorNext(tblID);
  532. if (status < 0)
  533. return status;
  534. if (status == 0)
  535. return count;
  536. }
  537. }
  538. /*****************************************************************************/
  539. LONG SGDatabase::Count(
  540. JET_TABLEID tblID,
  541. const CHAR *keyName) const
  542. {
  543. JET_ERR jetErr;
  544. LONG count,
  545. status;
  546. count = 0;
  547. status = PositionCursorFirst(tblID, keyName);
  548. if (status < 0)
  549. return status;
  550. if (status == 0)
  551. return 0;
  552. ASSERT(sesID != ~0);
  553. jetErr = JetIndexRecordCount(sesID, tblID, (ULONG *) &count, MAXLONG);
  554. if (jetErr != JET_errSuccess) {
  555. if (jetErr == JET_errNoCurrentRecord)
  556. return 0;
  557. DPRINTF((_T("JetIndexRecordCount: jetErr=%ld\n"), jetErr));
  558. return -1;
  559. }
  560. return count;
  561. }
  562. /*****************************************************************************/
  563. /********************** SGDatabase class public methods **********************/
  564. /*****************************************************************************/
  565. SGDatabase::SGDatabase()
  566. {
  567. fileName = NULL;
  568. sesID =
  569. tableID =
  570. queueID =
  571. stackID =
  572. listID = ~0U;
  573. dbID = ~0U;
  574. numTableEntries =
  575. numQueueEntries =
  576. numStackEntries =
  577. numListEntries = 0;
  578. numUncommittedTableEntries =
  579. numUncommittedQueueEntries =
  580. numUncommittedStackEntries =
  581. numUncommittedListEntries = 0;
  582. inTransaction = FALSE;
  583. if (!jetInitialized)
  584. InitializeEngine();
  585. numInstances++;
  586. }
  587. /*****************************************************************************/
  588. SGDatabase::~SGDatabase()
  589. {
  590. Close();
  591. ASSERT(fileName == NULL);
  592. ASSERT(sesID == ~0U);
  593. ASSERT(dbID == ~0U);
  594. ASSERT(tableID == ~0U);
  595. ASSERT(queueID == ~0U);
  596. ASSERT(stackID == ~0U);
  597. ASSERT(listID == ~0U);
  598. ASSERT(numTableEntries == 0);
  599. ASSERT(numQueueEntries == 0);
  600. ASSERT(numStackEntries == 0);
  601. ASSERT(numListEntries == 0);
  602. ASSERT(numUncommittedTableEntries == 0);
  603. ASSERT(numUncommittedQueueEntries == 0);
  604. ASSERT(numUncommittedStackEntries == 0);
  605. ASSERT(numUncommittedListEntries == 0);
  606. ASSERT(!inTransaction);
  607. if (--numInstances == 0 && jetInitialized) {
  608. TerminateEngine();
  609. }
  610. }
  611. /*****************************************************************************/
  612. BOOL SGDatabase::Create(const TCHAR *dbName)
  613. {
  614. CHAR szConnect[MAX_PATH];
  615. DWORD strLen1,
  616. strLen2;
  617. JET_ERR jetErr;
  618. ASSERT(fileName == NULL);
  619. ASSERT(sesID == ~0U);
  620. ASSERT(dbID == ~0U);
  621. ASSERT(tableID == ~0U);
  622. ASSERT(queueID == ~0U);
  623. ASSERT(stackID == ~0U);
  624. ASSERT(listID == ~0U);
  625. ASSERT(numTableEntries == 0);
  626. ASSERT(numQueueEntries == 0);
  627. ASSERT(numStackEntries == 0);
  628. ASSERT(numListEntries == 0);
  629. ASSERT(numUncommittedTableEntries == 0);
  630. ASSERT(numUncommittedQueueEntries == 0);
  631. ASSERT(numUncommittedStackEntries == 0);
  632. ASSERT(numUncommittedListEntries == 0);
  633. ASSERT(!inTransaction);
  634. if (!jetInitialized && !InitializeEngine())
  635. return FALSE;
  636. ASSERT(jetInitialized);
  637. jetErr = JetBeginSession(instance, &sesID, USERNAME, PASSWORD);
  638. if (jetErr != JET_errSuccess) {
  639. DPRINTF((_T("JetBeginSession: jetErr=%ld\n"), jetErr));
  640. Close();
  641. return FALSE;
  642. }
  643. DPRINTF((_T("JetBeginSession: sesID=%lu\n"), sesID));
  644. ASSERT(fileName == NULL);
  645. strLen1 = _tcslen(dbName);
  646. fileName = new CHAR[strLen1+1];
  647. ASSERT(fileName != NULL);
  648. #ifdef _UNICODE
  649. strLen2 = sprintf(fileName, "%S", dbName);
  650. #else
  651. strLen2 = sprintf(fileName, "%s", dbName);
  652. #endif
  653. ASSERT(strLen1 == strLen2);
  654. sprintf(szConnect, ";COUNTRY=%u;LANGID=0x%04x;CP=%u",
  655. COUNTRY_CODE, LANG_ID, CODE_PAGE);
  656. //
  657. // Create the database
  658. //
  659. jetErr = JetCreateDatabase(sesID, fileName, szConnect, &dbID, 0);
  660. if (jetErr == JET_errSuccess) {
  661. DPRINTF((_T("JetCreateDatabase(\"%s\"): dbID=%lu\n"),dbName, dbID));
  662. } else {
  663. if (jetErr != JET_errDatabaseDuplicate) {
  664. DPRINTF((_T("JetCreateDatabase(\"%s\"): jetErr=%ld\n"),
  665. dbName, jetErr));
  666. Close();
  667. return FALSE;
  668. }
  669. if (!DeleteFile(dbName)) {
  670. DPRINTF((_T("JetCreateDatabase: \"%s\" already exists and can't be deleted: %lu\n"),
  671. dbName, GetLastError()));
  672. Close();
  673. return FALSE;
  674. }
  675. jetErr = JetCreateDatabase(sesID, fileName, szConnect, &dbID, 0);
  676. if (jetErr != JET_errSuccess) {
  677. DPRINTF((_T("JetCreateDatabase: deleted old \"%s\"; jetErr=%ld\n"),
  678. dbName, jetErr));
  679. Close();
  680. return FALSE;
  681. }
  682. DPRINTF((_T("JetCreateDatabase: deleted old \"%s\"; new dbID=%lu\n"),
  683. dbName, dbID));
  684. }
  685. if (!CreateTable(TABLE_NAME, TABLE_NCOLS,
  686. tableColumnSpecs, tableColumnIDs, &tableID)) {
  687. Close();
  688. return FALSE;
  689. }
  690. if (!CreateIndex(tableID, TABLE_KEY_NAME_FILE_ID,
  691. TABLE_KEY_NCOLS_FILE_ID, tableKeyFileID)
  692. || !CreateIndex(tableID, TABLE_KEY_NAME_ATTR,
  693. TABLE_KEY_NCOLS_ATTR, tableKeyAttr)
  694. || !CreateIndex(tableID, TABLE_KEY_NAME_CSID,
  695. TABLE_KEY_NCOLS_CSID, tableKeyCSID)) {
  696. Close();
  697. return FALSE;
  698. }
  699. if (!CreateTable(QUEUE_NAME, QUEUE_NCOLS,
  700. queueColumnSpecs, queueColumnIDs, &queueID)) {
  701. Close();
  702. return FALSE;
  703. }
  704. if (!CreateIndex(queueID, QUEUE_KEY_NAME_READY_TIME,
  705. QUEUE_KEY_NCOLS_READY_TIME, queueKeyReadyTime)
  706. || !CreateIndex(queueID, QUEUE_KEY_NAME_FILE_ID,
  707. QUEUE_KEY_NCOLS_FILE_ID, queueKeyFileID)
  708. || !CreateIndex(queueID, QUEUE_KEY_NAME_ORDER,
  709. QUEUE_KEY_NCOLS_ORDER, queueKeyOrder)) {
  710. Close();
  711. return FALSE;
  712. }
  713. if (!CreateTable(STACK_NAME, STACK_NCOLS,
  714. stackColumnSpecs, stackColumnIDs, &stackID)) {
  715. Close();
  716. return FALSE;
  717. }
  718. if (!CreateIndex(stackID, STACK_KEY_NAME_FILE_ID,
  719. STACK_KEY_NCOLS_FILE_ID, stackKeyFileID)
  720. || !CreateIndex(stackID, STACK_KEY_NAME_ORDER,
  721. STACK_KEY_NCOLS_ORDER, stackKeyOrder)) {
  722. Close();
  723. return FALSE;
  724. }
  725. if (!CreateTable(LIST_NAME, LIST_NCOLS,
  726. listColumnSpecs, listColumnIDs, &listID)) {
  727. Close();
  728. return FALSE;
  729. }
  730. if (!CreateIndex(listID, LIST_KEY_NAME_NAME,
  731. LIST_KEY_NCOLS_NAME, listKeyName)) {
  732. Close();
  733. return FALSE;
  734. }
  735. return TRUE;
  736. }
  737. /*****************************************************************************/
  738. BOOL SGDatabase::Open(const TCHAR *dbName, BOOL is_log_drive)
  739. {
  740. SGNativeStackEntry stackEntry;
  741. JET_ERR jetErr;
  742. DWORD strLen1;
  743. #ifdef _UNICODE
  744. DWORD strLen2;
  745. #endif
  746. LONG status;
  747. ASSERT(sesID == ~0U);
  748. ASSERT(dbID == ~0U);
  749. ASSERT(tableID == ~0U);
  750. ASSERT(queueID == ~0U);
  751. ASSERT(stackID == ~0U);
  752. ASSERT(listID == ~0U);
  753. ASSERT(numTableEntries == 0);
  754. ASSERT(numQueueEntries == 0);
  755. ASSERT(numStackEntries == 0);
  756. ASSERT(numListEntries == 0);
  757. ASSERT(numUncommittedTableEntries == 0);
  758. ASSERT(numUncommittedQueueEntries == 0);
  759. ASSERT(numUncommittedStackEntries == 0);
  760. ASSERT(numUncommittedListEntries == 0);
  761. ASSERT(!inTransaction);
  762. // If this isn't the log drive, delete any log files that may exist
  763. // from a previous run. This is an abnormal condition that can arise
  764. // when the log drive is changing because of problems detected during
  765. // a previous startup.
  766. if (!is_log_drive) {
  767. WIN32_FIND_DATA findData;
  768. HANDLE fHandle;
  769. BOOL success;
  770. TFileName fName,
  771. delName;
  772. delName.assign(logDir);
  773. delName.append(_T("\\"));
  774. delName.append(DATABASE_DELETE_LOG_FILE_NAME);
  775. fHandle = FindFirstFile(delName.name, &findData);
  776. if (fHandle != INVALID_HANDLE_VALUE) {
  777. do {
  778. if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  779. success = GetParentName(delName.name, &fName);
  780. ASSERT(success); // internal error if failed
  781. fName.append(_T("\\"));
  782. fName.append(findData.cFileName);
  783. if (!DeleteFile(fName.name)) {
  784. DPRINTF((_T("SGDatabase::Open: can't delete \"%s\", %d\n"), delName.name, GetLastError()));
  785. }
  786. }
  787. } while (FindNextFile(fHandle, &findData));
  788. success = FindClose(fHandle);
  789. ASSERT(success);
  790. fHandle = NULL;
  791. }
  792. }
  793. if (!jetInitialized && !InitializeEngine()) {
  794. Close();
  795. return FALSE;
  796. }
  797. ASSERT(jetInitialized);
  798. jetErr = JetBeginSession(instance, &sesID, USERNAME, PASSWORD);
  799. if (jetErr != JET_errSuccess) {
  800. DPRINTF((_T("JetBeginSession: jetErr=%ld\n"), jetErr));
  801. Close();
  802. return FALSE;
  803. }
  804. DPRINTF((_T("JetBeginSession: sesID=%lu\n"), sesID));
  805. ASSERT(fileName == NULL);
  806. strLen1 = _tcslen(dbName);
  807. fileName = new CHAR[strLen1 + 1];
  808. ASSERT(fileName != NULL);
  809. #ifdef _UNICODE
  810. strLen2 = sprintf(fileName, "%S", dbName);
  811. #else
  812. strLen2 = sprintf(fileName, "%s", dbName);
  813. #endif
  814. ASSERT(strLen1 == strLen2);
  815. //
  816. // Open the database
  817. //
  818. jetErr = JetAttachDatabase(sesID, fileName, 0);
  819. if (jetErr != JET_errSuccess && jetErr != JET_wrnDatabaseAttached) {
  820. if (jetErr == JET_errFileNotFound) {
  821. DPRINTF((_T("JetAttachDatabase: \"%s\" not found\n"), dbName));
  822. } else {
  823. DPRINTF((_T("JetAttachDatabase(\"%s\"): jetErr=%ld\n"),
  824. dbName, jetErr));
  825. }
  826. Close();
  827. return FALSE;
  828. }
  829. jetErr = JetOpenDatabase(sesID, fileName, NULL, &dbID, 0);
  830. if (jetErr != JET_errSuccess) {
  831. DPRINTF((_T("JetOpenDatabase(\"%s\"): jetErr=%ld\n"), dbName, jetErr));
  832. Close();
  833. return FALSE;
  834. }
  835. DPRINTF((_T("JetOpenDatabase(\"%s\"): dbID=%lu\n"), dbName, dbID));
  836. if (!OpenTable(TABLE_NAME, TABLE_NCOLS, tableColumnSpecs,
  837. tableColumnIDs, &tableID)) {
  838. Close();
  839. return FALSE;
  840. }
  841. if (!OpenTable(QUEUE_NAME, QUEUE_NCOLS, queueColumnSpecs,
  842. queueColumnIDs, &queueID)) {
  843. Close();
  844. return FALSE;
  845. }
  846. if (!OpenTable(STACK_NAME, STACK_NCOLS, stackColumnSpecs,
  847. stackColumnIDs, &stackID)) {
  848. Close();
  849. return FALSE;
  850. }
  851. if (!OpenTable(LIST_NAME, LIST_NCOLS, listColumnSpecs,
  852. listColumnIDs, &listID)) {
  853. Close();
  854. return FALSE;
  855. }
  856. if ((numTableEntries = Count(tableID, TABLE_KEY_NAME_FILE_ID)) < 0
  857. || (numQueueEntries = Count(queueID, QUEUE_KEY_NAME_READY_TIME)) < 0
  858. || (numStackEntries = Count(stackID, STACK_KEY_NAME_FILE_ID)) < 0
  859. || (numListEntries = Count(listID, LIST_KEY_NAME_NAME)) < 0) {
  860. Close();
  861. return FALSE;
  862. }
  863. return TRUE;
  864. }
  865. /*****************************************************************************/
  866. BOOL SGDatabase::Close()
  867. {
  868. JET_ERR jetErr;
  869. int strLen;
  870. BOOL success = TRUE;
  871. if (inTransaction) {
  872. success = CommitTransaction();
  873. inTransaction = FALSE;
  874. }
  875. ASSERT(numUncommittedTableEntries == 0);
  876. ASSERT(numUncommittedQueueEntries == 0);
  877. ASSERT(numUncommittedStackEntries == 0);
  878. ASSERT(numUncommittedListEntries == 0);
  879. if (tableID != ~0U) {
  880. if (!CloseTable(tableID))
  881. success = FALSE;
  882. tableID = ~0U;
  883. }
  884. if (queueID != ~0U) {
  885. if (!CloseTable(queueID))
  886. success = FALSE;
  887. queueID = ~0U;
  888. }
  889. if (stackID != ~0U) {
  890. if (!CloseTable(stackID))
  891. success = FALSE;
  892. stackID = ~0U;
  893. }
  894. if (listID != ~0U) {
  895. if (!CloseTable(listID))
  896. success = FALSE;
  897. listID = ~0U;
  898. }
  899. if (dbID != ~0U) {
  900. ASSERT(fileName != NULL);
  901. ASSERT(sesID != ~0U);
  902. jetErr = JetCloseDatabase(sesID, dbID, 0);
  903. if (jetErr != JET_errSuccess) {
  904. DPRINTF((_T("JetCloseDatabase: jetErr=%ld\n"), jetErr));
  905. success = FALSE;
  906. }
  907. jetErr = JetDetachDatabase(sesID, fileName);
  908. if (jetErr != JET_errSuccess) {
  909. DPRINTF((_T("JetDetachDatabase: jetErr=%ld\n"), jetErr));
  910. success = FALSE;
  911. }
  912. dbID = ~0U;
  913. }
  914. if (sesID != ~0U) {
  915. jetErr = JetEndSession(sesID, 0);
  916. if (jetErr != JET_errSuccess) {
  917. DPRINTF((_T("JetEndSession: jetErr=%ld\n"), jetErr));
  918. success = FALSE;
  919. }
  920. sesID = ~0U;
  921. }
  922. if (fileName != NULL) {
  923. delete[] fileName;
  924. fileName = NULL;
  925. }
  926. numTableEntries =
  927. numQueueEntries =
  928. numStackEntries =
  929. numListEntries = 0;
  930. return success;
  931. }
  932. /*****************************************************************************/
  933. BOOL SGDatabase::BeginTransaction()
  934. {
  935. JET_ERR jetErr;
  936. ASSERT(!inTransaction);
  937. ASSERT(numUncommittedTableEntries == 0);
  938. ASSERT(numUncommittedQueueEntries == 0);
  939. ASSERT(numUncommittedStackEntries == 0);
  940. ASSERT(numUncommittedListEntries == 0);
  941. if (sesID == ~0U)
  942. return -1;
  943. jetErr = JetBeginTransaction(sesID);
  944. if (jetErr != JET_errSuccess) {
  945. DPRINTF((_T("JetBeginTransaction: jetErr=%ld\n"), jetErr));
  946. return FALSE;
  947. }
  948. inTransaction = TRUE;
  949. return TRUE;
  950. }
  951. /*****************************************************************************/
  952. BOOL SGDatabase::CommitTransaction()
  953. {
  954. JET_ERR jetErr;
  955. ASSERT(inTransaction);
  956. if (sesID == ~0U)
  957. return -1;
  958. jetErr = JetCommitTransaction(sesID, 0);
  959. if (jetErr != JET_errSuccess) {
  960. DPRINTF((_T("JetCommitTransaction: jetErr=%ld\n"), jetErr));
  961. return FALSE;
  962. }
  963. numTableEntries += numUncommittedTableEntries;
  964. numQueueEntries += numUncommittedQueueEntries;
  965. numStackEntries += numUncommittedStackEntries;
  966. numListEntries += numUncommittedListEntries;
  967. numUncommittedTableEntries = 0;
  968. numUncommittedQueueEntries = 0;
  969. numUncommittedStackEntries = 0;
  970. numUncommittedListEntries = 0;
  971. inTransaction = FALSE;
  972. return TRUE;
  973. }
  974. /*****************************************************************************/
  975. BOOL SGDatabase::AbortTransaction()
  976. {
  977. JET_ERR jetErr;
  978. ASSERT(inTransaction);
  979. inTransaction = FALSE;
  980. if (sesID == ~0U)
  981. return -1;
  982. jetErr = JetRollback(sesID, 0);
  983. if (jetErr != JET_errSuccess) {
  984. DPRINTF((_T("JetRollback: jetErr=%ld\n"), jetErr));
  985. return FALSE;
  986. }
  987. numUncommittedTableEntries = 0;
  988. numUncommittedQueueEntries = 0;
  989. numUncommittedStackEntries = 0;
  990. numUncommittedListEntries = 0;
  991. return TRUE;
  992. }
  993. /******************************* Table methods *******************************/
  994. LONG SGDatabase::TablePut(const SGNativeTableEntry *entry)
  995. {
  996. BOOL alreadyInTransaction = inTransaction;
  997. ASSERT(entry != NULL);
  998. if (sesID == ~0U
  999. || dbID == ~0U
  1000. || tableID == ~0U)
  1001. return -1;
  1002. if (!inTransaction && !BeginTransaction())
  1003. return -1;
  1004. ASSERT(inTransaction);
  1005. if (!PutData(tableID, entry, TABLE_NCOLS,
  1006. tableColumnSpecs, tableColumnIDs)) {
  1007. if (!alreadyInTransaction)
  1008. AbortTransaction();
  1009. return -1;
  1010. }
  1011. numUncommittedTableEntries++;
  1012. if (!alreadyInTransaction && !CommitTransaction())
  1013. return -1;
  1014. return 1;
  1015. }
  1016. /*****************************************************************************/
  1017. LONG SGDatabase::TableGetFirstByFileID(SGNativeTableEntry *entry) const
  1018. {
  1019. LONG status;
  1020. ASSERT(entry != NULL);
  1021. if (sesID == ~0U
  1022. || dbID == ~0U
  1023. || tableID == ~0U)
  1024. return -1;
  1025. status = PositionCursor(tableID, TABLE_KEY_NAME_FILE_ID,
  1026. entry, TABLE_KEY_NCOLS_FILE_ID, tableKeyFileID);
  1027. if (status <= 0)
  1028. return status;
  1029. return RetrieveData(tableID, entry, TABLE_NCOLS, tableColumnSpecs,
  1030. tableColumnIDs, TABLE_EXCLUDE_FILE_ID_MASK ) ? 1 : -1;
  1031. }
  1032. /*****************************************************************************/
  1033. LONG SGDatabase::TableGetFirstByAttr(SGNativeTableEntry *entry) const
  1034. {
  1035. LONG status;
  1036. ASSERT(entry != NULL);
  1037. if (sesID == ~0U
  1038. || dbID == ~0U
  1039. || tableID == ~0U)
  1040. return -1;
  1041. status = PositionCursor(tableID, TABLE_KEY_NAME_ATTR,
  1042. entry, TABLE_KEY_NCOLS_ATTR, tableKeyAttr);
  1043. if (status <= 0)
  1044. return status;
  1045. return RetrieveData(tableID, entry, TABLE_NCOLS, tableColumnSpecs,
  1046. tableColumnIDs, TABLE_EXCLUDE_ATTR_MASK) ? 1 : -1;
  1047. }
  1048. /*****************************************************************************/
  1049. LONG SGDatabase::TableGetFirstByCSIndex(SGNativeTableEntry *entry) const
  1050. {
  1051. LONG status;
  1052. ASSERT(entry != NULL);
  1053. if (sesID == ~0U
  1054. || dbID == ~0U
  1055. || tableID == ~0U)
  1056. return -1;
  1057. status = PositionCursor(tableID, TABLE_KEY_NAME_CSID,
  1058. entry, TABLE_KEY_NCOLS_CSID, tableKeyCSID);
  1059. if (status <= 0)
  1060. return status;
  1061. return RetrieveData(tableID, entry, TABLE_NCOLS, tableColumnSpecs,
  1062. tableColumnIDs, TABLE_EXCLUDE_CS_INDEX_MASK) ? 1 : -1;
  1063. }
  1064. /*****************************************************************************/
  1065. LONG SGDatabase::TableGetNext(SGNativeTableEntry *entry) const
  1066. {
  1067. LONG status;
  1068. ASSERT(entry != NULL);
  1069. if (sesID == ~0U
  1070. || dbID == ~0U
  1071. || tableID == ~0U)
  1072. return -1;
  1073. status = PositionCursorNext(tableID);
  1074. if (status <= 0)
  1075. return status;
  1076. return RetrieveData(tableID, entry, TABLE_NCOLS,
  1077. tableColumnSpecs, tableColumnIDs, GET_ALL_MASK) ? 1 : -1;
  1078. }
  1079. /*****************************************************************************/
  1080. LONG SGDatabase::TableDeleteByFileID(DWORDLONG fileID)
  1081. {
  1082. SGNativeTableEntry entry;
  1083. LONG status;
  1084. BOOL alreadyInTransaction = inTransaction;
  1085. if (sesID == ~0U
  1086. || dbID == ~0U
  1087. || tableID == ~0U)
  1088. return -1;
  1089. entry.fileID = fileID;
  1090. status = PositionCursor(tableID, TABLE_KEY_NAME_FILE_ID,
  1091. &entry, TABLE_KEY_NCOLS_FILE_ID, tableKeyFileID);
  1092. if (status <= 0)
  1093. return status;
  1094. if (!inTransaction && !BeginTransaction())
  1095. return -1;
  1096. ASSERT(inTransaction);
  1097. status = Delete(tableID);
  1098. if (status < 0) {
  1099. if (!alreadyInTransaction)
  1100. AbortTransaction();
  1101. return -1;
  1102. }
  1103. numUncommittedTableEntries -= status;
  1104. if (!alreadyInTransaction && !CommitTransaction())
  1105. return -1;
  1106. return status;
  1107. }
  1108. /*****************************************************************************/
  1109. LONG SGDatabase::TableDeleteByCSIndex(const CSID *csIndex)
  1110. {
  1111. SGNativeTableEntry entry;
  1112. LONG status;
  1113. BOOL alreadyInTransaction = inTransaction;
  1114. ASSERT(csIndex != NULL);
  1115. if (sesID == ~0U
  1116. || dbID == ~0U
  1117. || tableID == ~0U)
  1118. return -1;
  1119. entry.csIndex = *csIndex;
  1120. status = PositionCursor(tableID, TABLE_KEY_NAME_CSID,
  1121. &entry, TABLE_KEY_NCOLS_CSID, tableKeyCSID);
  1122. if (status <= 0)
  1123. return status;
  1124. if (!inTransaction && !BeginTransaction())
  1125. return -1;
  1126. ASSERT(inTransaction);
  1127. status = Delete(tableID);
  1128. if (status < 0) {
  1129. if (!alreadyInTransaction)
  1130. AbortTransaction();
  1131. return -1;
  1132. }
  1133. numUncommittedTableEntries -= status;
  1134. if (!alreadyInTransaction && !CommitTransaction())
  1135. return -1;
  1136. return status;
  1137. }
  1138. /*****************************************************************************/
  1139. LONG SGDatabase::TableCount() const
  1140. {
  1141. LONG numEntries;
  1142. if (sesID == ~0U
  1143. || dbID == ~0U
  1144. || tableID == ~0U)
  1145. return -1;
  1146. numEntries = numTableEntries + numUncommittedTableEntries;
  1147. ASSERT(numEntries >= 0);
  1148. ASSERT(Count(tableID, TABLE_KEY_NAME_FILE_ID) == numEntries);
  1149. return numEntries;
  1150. }
  1151. /******************************* Queue methods *******************************/
  1152. LONG SGDatabase::QueuePut(SGNativeQueueEntry *entry)
  1153. {
  1154. BOOL alreadyInTransaction = inTransaction;
  1155. ASSERT(entry != NULL);
  1156. if (sesID == ~0U
  1157. || dbID == ~0U
  1158. || queueID == ~0U)
  1159. return -1;
  1160. if (!inTransaction && !BeginTransaction())
  1161. return -1;
  1162. ASSERT(inTransaction);
  1163. if (!PutData(queueID, entry, QUEUE_NCOLS,
  1164. queueColumnSpecs, queueColumnIDs)) {
  1165. if (!alreadyInTransaction)
  1166. AbortTransaction();
  1167. return -1;
  1168. }
  1169. numUncommittedQueueEntries++;
  1170. if (!alreadyInTransaction && !CommitTransaction())
  1171. return -1;
  1172. return 1;
  1173. }
  1174. /*****************************************************************************/
  1175. LONG SGDatabase::QueueGetFirst(SGNativeQueueEntry *entry) const
  1176. {
  1177. LONG status;
  1178. ASSERT(entry != NULL);
  1179. if (sesID == ~0U
  1180. || dbID == ~0U
  1181. || queueID == ~0U)
  1182. return -1;
  1183. status = PositionCursorFirst(queueID, QUEUE_KEY_NAME_READY_TIME);
  1184. if (status <= 0)
  1185. return status;
  1186. return RetrieveData(queueID, entry, QUEUE_NCOLS,
  1187. queueColumnSpecs, queueColumnIDs, GET_ALL_MASK) ? 1 : -1;
  1188. }
  1189. /*****************************************************************************/
  1190. LONG SGDatabase::QueueGetFirstByFileID(SGNativeQueueEntry *entry) const
  1191. {
  1192. LONG status;
  1193. ASSERT(entry != NULL);
  1194. if (sesID == ~0U
  1195. || dbID == ~0U
  1196. || queueID == ~0U)
  1197. return -1;
  1198. status = PositionCursor(queueID, QUEUE_KEY_NAME_FILE_ID,
  1199. entry, QUEUE_KEY_NCOLS_FILE_ID, queueKeyFileID);
  1200. if (status <= 0)
  1201. return status;
  1202. return RetrieveData(queueID, entry, QUEUE_NCOLS, queueColumnSpecs,
  1203. queueColumnIDs, QUEUE_EXCLUDE_FILE_ID_MASK) ? 1 : -1;
  1204. }
  1205. /*****************************************************************************/
  1206. LONG SGDatabase::QueueGetNext(SGNativeQueueEntry *entry) const
  1207. {
  1208. LONG status;
  1209. ASSERT(entry != NULL);
  1210. if (sesID == ~0U
  1211. || dbID == ~0U
  1212. || queueID == ~0U)
  1213. return -1;
  1214. status = PositionCursorNext(queueID);
  1215. if (status <= 0)
  1216. return status;
  1217. return RetrieveData(queueID, entry, QUEUE_NCOLS,
  1218. queueColumnSpecs, queueColumnIDs, GET_ALL_MASK) ? 1 : -1;
  1219. }
  1220. /*****************************************************************************/
  1221. LONG SGDatabase::QueueDelete(DWORD order)
  1222. {
  1223. SGNativeQueueEntry entry;
  1224. LONG status;
  1225. BOOL alreadyInTransaction = inTransaction;
  1226. ASSERT(sesID != ~0U);
  1227. ASSERT(dbID != ~0U);
  1228. ASSERT(queueID != ~0U);
  1229. entry.order = order;
  1230. status = PositionCursor(queueID, QUEUE_KEY_NAME_ORDER,
  1231. &entry, QUEUE_KEY_NCOLS_ORDER, queueKeyOrder);
  1232. if (status <= 0)
  1233. return status;
  1234. if (!inTransaction && !BeginTransaction())
  1235. return -1;
  1236. ASSERT(inTransaction);
  1237. status = Delete(queueID);
  1238. ASSERT(status <= 1);
  1239. if (status < 0) {
  1240. if (!alreadyInTransaction)
  1241. AbortTransaction();
  1242. return -1;
  1243. }
  1244. numUncommittedQueueEntries -= status;
  1245. if (!alreadyInTransaction && !CommitTransaction())
  1246. return -1;
  1247. return status;
  1248. }
  1249. /*****************************************************************************/
  1250. LONG SGDatabase::QueueDeleteByFileID(DWORDLONG fileID)
  1251. {
  1252. SGNativeQueueEntry entry;
  1253. LONG status;
  1254. BOOL alreadyInTransaction = inTransaction;
  1255. if (sesID == ~0U
  1256. || dbID == ~0U
  1257. || queueID == ~0U)
  1258. return -1;
  1259. entry.fileID = fileID;
  1260. status = PositionCursor(queueID, QUEUE_KEY_NAME_FILE_ID,
  1261. &entry, QUEUE_KEY_NCOLS_FILE_ID, queueKeyFileID);
  1262. if (status <= 0)
  1263. return status;
  1264. if (!inTransaction && !BeginTransaction())
  1265. return -1;
  1266. ASSERT(inTransaction);
  1267. status = Delete(queueID);
  1268. if (status < 0) {
  1269. if (!alreadyInTransaction)
  1270. AbortTransaction();
  1271. return -1;
  1272. }
  1273. numUncommittedQueueEntries -= status;
  1274. if (!alreadyInTransaction && !CommitTransaction())
  1275. return -1;
  1276. return status;
  1277. }
  1278. /*****************************************************************************/
  1279. LONG SGDatabase::QueueCount() const
  1280. {
  1281. LONG numEntries;
  1282. if (sesID == ~0U
  1283. || dbID == ~0U
  1284. || queueID == ~0U)
  1285. return -1;
  1286. numEntries = numQueueEntries + numUncommittedQueueEntries;
  1287. ASSERT(numEntries >= 0);
  1288. ASSERT(Count(queueID, QUEUE_KEY_NAME_READY_TIME) == numEntries);
  1289. return numEntries;
  1290. }
  1291. /******************************* Stack methods *******************************/
  1292. LONG SGDatabase::StackPut(DWORDLONG fileID, BOOL done)
  1293. {
  1294. SGNativeStackEntry entry;
  1295. LONG status;
  1296. BOOL alreadyInTransaction = inTransaction;
  1297. if (sesID == ~0U
  1298. || dbID == ~0U
  1299. || stackID == ~0U)
  1300. return -1;
  1301. if (done)
  1302. entry.order = 0;
  1303. else {
  1304. status = PositionCursorLast(stackID, STACK_KEY_NAME_ORDER);
  1305. if (status < 0)
  1306. return -1;
  1307. if (status == 0)
  1308. entry.order = 1;
  1309. else {
  1310. if (!RetrieveData(stackID, &entry, STACK_NCOLS,
  1311. stackColumnSpecs, stackColumnIDs, STACK_GET_ORDER_ONLY_MASK))
  1312. return -1;
  1313. entry.order++;
  1314. }
  1315. }
  1316. entry.fileID = fileID;
  1317. if (!inTransaction && !BeginTransaction())
  1318. return -1;
  1319. ASSERT(inTransaction);
  1320. if (!PutData(stackID, &entry, STACK_NCOLS,
  1321. stackColumnSpecs, stackColumnIDs)) {
  1322. if (!alreadyInTransaction)
  1323. AbortTransaction();
  1324. return -1;
  1325. }
  1326. numUncommittedStackEntries++;
  1327. if (!alreadyInTransaction && !CommitTransaction())
  1328. return -1;
  1329. return 1;
  1330. }
  1331. /*****************************************************************************/
  1332. LONG SGDatabase::StackGetTop(SGNativeStackEntry *entry) const
  1333. {
  1334. LONG status;
  1335. ASSERT(entry != NULL);
  1336. if (sesID == ~0U
  1337. || dbID == ~0U
  1338. || stackID == ~0U)
  1339. return -1;
  1340. status = PositionCursorLast(stackID, STACK_KEY_NAME_ORDER);
  1341. if (status <= 0)
  1342. return status;
  1343. status = RetrieveData(stackID, entry, STACK_NCOLS,
  1344. stackColumnSpecs, stackColumnIDs, GET_ALL_MASK);
  1345. if (status < 0)
  1346. return status;
  1347. ASSERT(status == 1);
  1348. return entry->order == 0 ? 0 : 1;
  1349. }
  1350. /*****************************************************************************/
  1351. LONG SGDatabase::StackGetFirstByFileID(SGNativeStackEntry *entry) const
  1352. {
  1353. LONG status;
  1354. ASSERT(entry != NULL);
  1355. if (sesID == ~0U
  1356. || dbID == ~0U
  1357. || stackID == ~0U)
  1358. return -1;
  1359. status = PositionCursor(stackID, STACK_KEY_NAME_FILE_ID,
  1360. entry, STACK_KEY_NCOLS_FILE_ID, stackKeyFileID);
  1361. if (status <= 0)
  1362. return status;
  1363. return RetrieveData(stackID, entry, STACK_NCOLS, stackColumnSpecs,
  1364. stackColumnIDs, STACK_EXCLUDE_FILE_ID_MASK) ? 1 : -1;
  1365. }
  1366. /*****************************************************************************/
  1367. LONG SGDatabase::StackGetNext(SGNativeStackEntry *entry) const
  1368. {
  1369. LONG status;
  1370. ASSERT(entry != NULL);
  1371. if (sesID == ~0U
  1372. || dbID == ~0U
  1373. || stackID == ~0U)
  1374. return -1;
  1375. status = PositionCursorNext(stackID);
  1376. if (status <= 0)
  1377. return status;
  1378. return RetrieveData(stackID, entry, STACK_NCOLS,
  1379. stackColumnSpecs, stackColumnIDs, GET_ALL_MASK) ? 1 : -1;
  1380. }
  1381. /*****************************************************************************/
  1382. LONG SGDatabase::StackDelete(DWORD order)
  1383. {
  1384. SGNativeStackEntry entry;
  1385. LONG status;
  1386. BOOL alreadyInTransaction = inTransaction;
  1387. if (sesID == ~0U
  1388. || dbID == ~0U
  1389. || stackID == ~0U)
  1390. return -1;
  1391. entry.order = order;
  1392. status = PositionCursor(stackID, STACK_KEY_NAME_ORDER,
  1393. &entry, STACK_KEY_NCOLS_ORDER, stackKeyOrder);
  1394. if (status <= 0)
  1395. return status;
  1396. if (!inTransaction && !BeginTransaction())
  1397. return -1;
  1398. ASSERT(inTransaction);
  1399. status = Delete(stackID);
  1400. ASSERT(order == 0 || status <= 1);
  1401. if (status < 0) {
  1402. if (!alreadyInTransaction)
  1403. AbortTransaction();
  1404. return -1;
  1405. }
  1406. numUncommittedStackEntries -= status;
  1407. if (!alreadyInTransaction && !CommitTransaction())
  1408. return -1;
  1409. return status;
  1410. }
  1411. /*****************************************************************************/
  1412. LONG SGDatabase::StackDeleteByFileID(DWORDLONG fileID)
  1413. {
  1414. SGNativeStackEntry entry;
  1415. LONG status;
  1416. BOOL alreadyInTransaction = inTransaction;
  1417. if (sesID == ~0U
  1418. || dbID == ~0U
  1419. || stackID == ~0U)
  1420. return -1;
  1421. entry.fileID = fileID;
  1422. status = PositionCursor(stackID, STACK_KEY_NAME_FILE_ID,
  1423. &entry, STACK_KEY_NCOLS_FILE_ID, stackKeyFileID);
  1424. if (status <= 0)
  1425. return status;
  1426. if (!inTransaction && !BeginTransaction())
  1427. return -1;
  1428. ASSERT(inTransaction);
  1429. status = Delete(stackID);
  1430. if (status < 0) {
  1431. if (!alreadyInTransaction)
  1432. AbortTransaction();
  1433. return -1;
  1434. }
  1435. numUncommittedStackEntries -= status;
  1436. if (!alreadyInTransaction && !CommitTransaction())
  1437. return -1;
  1438. return status;
  1439. }
  1440. /*****************************************************************************/
  1441. LONG SGDatabase::StackCount() const
  1442. {
  1443. LONG numEntries;
  1444. if (sesID == ~0U
  1445. || dbID == ~0U
  1446. || stackID == ~0U)
  1447. return -1;
  1448. numEntries = numStackEntries + numUncommittedStackEntries;
  1449. ASSERT(numEntries >= 0);
  1450. ASSERT(Count(stackID, STACK_KEY_NAME_ORDER) == numEntries);
  1451. return numEntries;
  1452. }
  1453. /******************************* List methods ********************************/
  1454. LONG SGDatabase::ListWrite(const SGNativeListEntry *entry)
  1455. {
  1456. LONG status;
  1457. BOOL alreadyInTransaction = inTransaction;
  1458. ASSERT(entry != NULL);
  1459. ASSERT(entry->name != NULL);
  1460. if (sesID == ~0U
  1461. || dbID == ~0U
  1462. || listID == ~0U)
  1463. return -1;
  1464. // May want to overwrite the entry directly instead of deleting and inserting
  1465. if (!inTransaction && !BeginTransaction())
  1466. return -1;
  1467. ASSERT(inTransaction);
  1468. status = ListDelete(entry->name);
  1469. ASSERT(status <= 1);
  1470. if (status < 0
  1471. || !PutData(listID, entry, LIST_NCOLS,
  1472. listColumnSpecs, listColumnIDs)) {
  1473. if (!alreadyInTransaction)
  1474. AbortTransaction();
  1475. return -1;
  1476. }
  1477. if (status == 0)
  1478. numUncommittedListEntries++;
  1479. if (!alreadyInTransaction && !CommitTransaction())
  1480. return -1;
  1481. return 1;
  1482. }
  1483. /*****************************************************************************/
  1484. LONG SGDatabase::ListRead(SGNativeListEntry *entry) const
  1485. {
  1486. LONG status;
  1487. ASSERT(entry != NULL);
  1488. ASSERT(entry->name != NULL);
  1489. if (sesID == ~0U
  1490. || dbID == ~0U
  1491. || listID == ~0U)
  1492. return -1;
  1493. status = PositionCursor(listID, LIST_KEY_NAME_NAME,
  1494. entry, LIST_KEY_NCOLS_NAME, listKeyName);
  1495. if (status <= 0)
  1496. return status;
  1497. return RetrieveData(listID, entry, LIST_NCOLS, listColumnSpecs,
  1498. listColumnIDs, LIST_EXCLUDE_NAME_MASK) ? 1 : -1;
  1499. }
  1500. /*****************************************************************************/
  1501. LONG SGDatabase::ListDelete(const TCHAR *name)
  1502. {
  1503. SGNativeListEntry entry;
  1504. LONG status;
  1505. BOOL alreadyInTransaction = inTransaction;
  1506. ASSERT(name != NULL);
  1507. if (sesID == ~0U
  1508. || dbID == ~0U
  1509. || listID == ~0U)
  1510. return -1;
  1511. entry.name = name;
  1512. entry.value = NULL;
  1513. status = PositionCursor(listID, LIST_KEY_NAME_NAME,
  1514. &entry, LIST_KEY_NCOLS_NAME, listKeyName);
  1515. if (status <= 0)
  1516. return status;
  1517. if (!inTransaction && !BeginTransaction())
  1518. return -1;
  1519. ASSERT(inTransaction);
  1520. status = Delete(listID);
  1521. if (status < 0) {
  1522. if (!alreadyInTransaction)
  1523. AbortTransaction();
  1524. return -1;
  1525. }
  1526. return status;
  1527. }
  1528. /*****************************************************************************/
  1529. LONG SGDatabase::ListCount() const
  1530. {
  1531. LONG numEntries;
  1532. if (sesID == ~0U
  1533. || dbID == ~0U
  1534. || listID == ~0U)
  1535. return -1;
  1536. numEntries = numListEntries + numUncommittedListEntries;
  1537. ASSERT(numEntries >= 0);
  1538. ASSERT(Count(listID, LIST_KEY_NAME_NAME) == numEntries);
  1539. return numEntries;
  1540. }
  1541.