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.

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