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.

799 lines
23 KiB

  1. /////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Microsoft WMIOLE DB Provider
  4. // (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // Hashing routines for row manipulation.
  7. //
  8. /////////////////////////////////////////////////////////////////////////////////////
  9. #include "headers.h"
  10. #include "hashtbl.h"
  11. /////////////////////////////////////////////////////////////////////////////////////////
  12. // Constructor
  13. /////////////////////////////////////////////////////////////////////////////////////////
  14. _COLUMNDATA::_COLUMNDATA()
  15. {
  16. dwLength = 0;
  17. dwStatus = 0;
  18. dwType = 0;
  19. pbData= NULL;
  20. }
  21. /////////////////////////////////////////////////////////////////////////////////////////
  22. // Destructor
  23. /////////////////////////////////////////////////////////////////////////////////////////
  24. _COLUMNDATA::~_COLUMNDATA()
  25. {
  26. CDataMap Map;
  27. Map.FreeData(dwType,pbData);
  28. }
  29. /////////////////////////////////////////////////////////////////////////////////////////
  30. // Function to set column information for the current column
  31. // NTRaid:111827 111828
  32. // 06/07/00
  33. /////////////////////////////////////////////////////////////////////////////////////////
  34. HRESULT _COLUMNDATA::SetData(CVARIANT & vVar , DWORD dwColType )
  35. {
  36. HRESULT hr = S_OK;
  37. CDataMap Map;
  38. // NTRaid:111828
  39. // 06/13/00
  40. WORD wType = -1;
  41. // NTRaid:111827
  42. // 06/13/00
  43. DWORD dwFlags = 0;
  44. dwStatus = E_UNEXPECTED;
  45. //=================================================================
  46. // This will set the type of the column in _COLUMNDATA
  47. //=================================================================
  48. hr = Map.MapCIMTypeToOLEDBType(vVar.GetType(),wType,dwLength,dwFlags);
  49. dwType = wType;
  50. if( dwColType == CIM_DATETIME || dwColType == DBTYPE_DBTIMESTAMP)
  51. {
  52. dwType = CIM_DATETIME;
  53. }
  54. //=================================================================================
  55. // This is done so as AllocateAndMapCIMTypeToOLEDBType should convert from
  56. // Variant DATE format to DBTIMESTAMP format
  57. //=================================================================================
  58. if( vVar.GetType() == VT_DATE)
  59. {
  60. dwType = VT_DATE;
  61. }
  62. if( dwColType == VT_VARIANT)
  63. {
  64. dwType = (DBTYPE)dwColType;
  65. }
  66. if(dwColType == CIM_IUNKNOWN)
  67. {
  68. dwType = CIM_IUNKNOWN;
  69. }
  70. hr = Map.AllocateAndMapCIMTypeToOLEDBType(vVar,pbData,dwType, dwLength,dwFlags);
  71. if(SUCCEEDED(hr)){
  72. //=============================================================================
  73. // SetData returns the status of the Data setting if it has not failed
  74. //=============================================================================
  75. dwStatus = hr;
  76. if((dwColType == (CIM_DATETIME | CIM_FLAG_ARRAY)) || (dwColType == (DBTYPE_DBTIMESTAMP | CIM_FLAG_ARRAY)) )
  77. {
  78. dwType = (DBTYPE)dwColType;
  79. }
  80. else
  81. if(dwType == CIM_IUNKNOWN)
  82. {
  83. dwType = DBTYPE_IUNKNOWN;
  84. }
  85. hr = S_OK;
  86. }
  87. return hr;
  88. }
  89. /////////////////////////////////////////////////////////////////////////////////////////
  90. // Function to reset the column data. This frees column data
  91. /////////////////////////////////////////////////////////////////////////////////////////
  92. void _COLUMNDATA::ReleaseColumnData( )
  93. {
  94. CDataMap Map;
  95. if(pbData != NULL)
  96. {
  97. Map.FreeData(dwType,pbData);
  98. }
  99. }
  100. /////////////////////////////////////////////////////////////////////////////////////////
  101. // Get pointer to a particular columndata
  102. /////////////////////////////////////////////////////////////////////////////////////////
  103. PCOLUMNDATA tagRowBuff::GetColumnData(int iCol)
  104. {
  105. return (pdData + iCol);
  106. }
  107. /////////////////////////////////////////////////////////////////////////////////////////
  108. // Set the rowdata pointer
  109. /////////////////////////////////////////////////////////////////////////////////////////
  110. HRESULT tagRowBuff::SetRowData(PCOLUMNDATA pColData)
  111. {
  112. pdData = pColData;
  113. return S_OK;
  114. }
  115. /////////////////////////////////////////////////////////////////////////////////////
  116. //
  117. // Allocates a contiguous block of the required number of slots.
  118. //
  119. // Returns one of the following values:
  120. // S_OK slot allocate succeeded
  121. // E_OUTOFMEMORY slot allocation failed because of memory allocation problem
  122. /////////////////////////////////////////////////////////////////////////////////////
  123. HRESULT GetNextSlots ( PLSTSLOT plstslot, //IN slot list
  124. HSLOT cslot, //IN needed block size (in slots)
  125. HSLOT* pislot //IN handle of the first slot in the returned block
  126. )
  127. {
  128. HSLOT islot, dslot;
  129. PSLOT pslot, pslotTmp;
  130. LONG_PTR cbCommit;
  131. HRESULT hr = S_OK;
  132. if (plstslot->islotRov)
  133. {
  134. plstslot->islotRov = ((PSLOT) & plstslot->rgslot[(plstslot->islotRov * plstslot->cbSlot)-sizeof(SLOT)])->islotNext;
  135. }
  136. else
  137. {
  138. plstslot->islotRov = plstslot->islotFirst;
  139. }
  140. islot = plstslot->islotRov;
  141. while (islot)
  142. {
  143. if (((PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)])->cslot >= cslot)
  144. {
  145. break;
  146. }
  147. islot = ((PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)])->islotNext;
  148. }
  149. if (islot == 0)
  150. {
  151. islot = plstslot->islotFirst;
  152. while (islot != plstslot->islotRov)
  153. {
  154. if (((PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)])->cslot >= cslot)
  155. {
  156. break;
  157. }
  158. islot = ((PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)])->islotNext;
  159. }
  160. if (islot == plstslot->islotRov)
  161. islot = 0;
  162. }
  163. if (islot == 0)
  164. {
  165. cbCommit = ((cslot *plstslot->cbSlot) / plstslot->cbPage + 1) *plstslot->cbPage;
  166. if ((plstslot->cbCommitCurrent + cbCommit) > plstslot->cbCommitMax
  167. || VirtualAlloc((VOID *) ((BYTE *) plstslot + plstslot->cbCommitCurrent),
  168. cbCommit,
  169. MEM_COMMIT,
  170. PAGE_READWRITE ) == NULL)
  171. {
  172. hr = E_OUTOFMEMORY ;
  173. }
  174. else
  175. {
  176. islot = (HSLOT) ((plstslot->cbCommitCurrent + plstslot->cbExtra) / plstslot->cbSlot);
  177. dslot = ((cbCommit + plstslot->cbslotLeftOver) / plstslot->cbSlot);
  178. if ((plstslot->pbitsSlot)->IsSlotSet( islot - 1 ) != NOERROR)
  179. {
  180. if ((plstslot->pbitsSlot)->FindSet( islot - 1, plstslot->islotMin, &islot ) == NOERROR)
  181. {
  182. islot++;
  183. }
  184. else
  185. {
  186. islot = plstslot->islotMin;
  187. }
  188. pslot = (PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)];
  189. pslot->cslot += dslot;
  190. DecoupleSlot( plstslot, islot, pslot );
  191. }
  192. else
  193. {
  194. // pslot = (PSLOT) ((BYTE *) plstslot + plstslot->cbCommitCurrent - plstslot->cbslotLeftOver);
  195. pslot = (PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)];
  196. pslot->cslot = dslot;
  197. }
  198. pslot->islotNext = plstslot->islotFirst;
  199. pslot->islotPrev = 0;
  200. plstslot->islotMax += dslot;
  201. plstslot->islotFirst = islot;
  202. plstslot->cbslotLeftOver = (cbCommit + plstslot->cbslotLeftOver) % plstslot->cbSlot;
  203. plstslot->cbCommitCurrent += cbCommit;
  204. if (pslot->islotNext)
  205. {
  206. ((PSLOT) & plstslot->rgslot[(pslot->islotNext *plstslot->cbSlot)-sizeof(SLOT)])->islotPrev = islot;
  207. }
  208. islot = plstslot->islotFirst;
  209. }
  210. }
  211. if(SUCCEEDED(hr))
  212. {
  213. pslot = (PSLOT) & plstslot->rgslot[(islot *plstslot->cbSlot)-sizeof(SLOT)];
  214. DecoupleSlot( plstslot, islot, pslot );
  215. if (pslot->cslot > cslot)
  216. {
  217. pslotTmp = (PSLOT) & plstslot->rgslot[ ((islot + cslot) *plstslot->cbSlot)-sizeof(SLOT)];
  218. pslotTmp->cslot = pslot->cslot - cslot;
  219. AddSlotToList( plstslot, islot + cslot, pslotTmp );
  220. }
  221. if (SUCCEEDED( hr = (plstslot->pbitsSlot)->SetSlots( islot, islot + cslot - 1 )))
  222. {
  223. if (pislot)
  224. {
  225. *pislot = islot;
  226. }
  227. }
  228. }
  229. return hr;
  230. }
  231. /////////////////////////////////////////////////////////////////////////////////////
  232. //
  233. // Decouples a slot from the list of free slots
  234. //
  235. // NONE
  236. //
  237. /////////////////////////////////////////////////////////////////////////////////////
  238. VOID DecoupleSlot ( PLSTSLOT plstslot, //IN slot list
  239. HSLOT islot, //IN slot handle to decouple
  240. PSLOT pslot //IN pointer to the slot header
  241. )
  242. {
  243. PSLOT slotTemp = NULL;
  244. if (pslot->islotNext)
  245. {
  246. slotTemp = (PSLOT) & plstslot->rgslot[(pslot->islotNext *plstslot->cbSlot)-sizeof(SLOT)];
  247. slotTemp->islotNext = pslot->islotPrev;
  248. ((PSLOT) & plstslot->rgslot[(pslot->islotNext *plstslot->cbSlot)-sizeof(SLOT)])->islotPrev = pslot->islotPrev;
  249. }
  250. if (pslot->islotPrev)
  251. {
  252. ((PSLOT) & plstslot->rgslot[(pslot->islotPrev *plstslot->cbSlot)-sizeof(SLOT)])->islotNext = pslot->islotNext;
  253. }
  254. else
  255. {
  256. plstslot->islotFirst = pslot->islotNext;
  257. }
  258. if (islot == plstslot->islotRov)
  259. {
  260. plstslot->islotRov = pslot->islotNext;
  261. }
  262. }
  263. /////////////////////////////////////////////////////////////////////////////////////
  264. //
  265. // Adds a slot to the list of free slots
  266. //
  267. // NONE
  268. //
  269. /////////////////////////////////////////////////////////////////////////////////////
  270. VOID AddSlotToList ( PLSTSLOT plstslot, //IN slot list
  271. HSLOT islot, //IN slot handle
  272. PSLOT pslot //IN pointer to the slot header
  273. )
  274. {
  275. pslot->islotPrev = 0;
  276. pslot->islotNext = plstslot->islotFirst;
  277. plstslot->islotFirst = islot;
  278. if (pslot->islotNext)
  279. {
  280. ((PSLOT) & plstslot->rgslot[(pslot->islotNext *plstslot->cbSlot)-sizeof(SLOT)])->islotPrev = islot;
  281. }
  282. }
  283. /////////////////////////////////////////////////////////////////////////////////////
  284. // ReleaseSlots
  285. //
  286. // Releases a contiguous block of slots.
  287. //
  288. // Returns one of the following values:
  289. // S_OK | method succeeded
  290. //
  291. /////////////////////////////////////////////////////////////////////////////////////
  292. HRESULT ReleaseSlots ( PLSTSLOT plstslot, //IN slot list
  293. HSLOT islot, //IN handle of first slot to release
  294. ULONG_PTR cslot //IN count of slots to release
  295. )
  296. {
  297. PSLOT pslot, pslotTmp;
  298. (plstslot->pbitsSlot)->ResetSlots( islot, islot + cslot - 1 );
  299. pslot = (PSLOT) & plstslot->rgslot[(islot * plstslot->cbSlot)-sizeof(SLOT)];
  300. pslot->cslot = cslot;
  301. if (islot > plstslot->islotMin && (plstslot->pbitsSlot)->IsSlotSet( islot - 1 ) != NOERROR)
  302. {
  303. if ((plstslot->pbitsSlot)->FindSet( islot - 1, plstslot->islotMin, &islot ) == NOERROR)
  304. {
  305. islot++;
  306. }
  307. else
  308. {
  309. islot = plstslot->islotMin;
  310. }
  311. pslot = (PSLOT) & plstslot->rgslot[(islot * plstslot->cbSlot)-sizeof(SLOT)];
  312. pslot->cslot += cslot;
  313. DecoupleSlot( plstslot, islot, pslot );
  314. }
  315. else
  316. if ((islot + cslot) <= (ULONG_PTR)plstslot->islotMax && (plstslot->pbitsSlot)->IsSlotSet( islot + cslot ) != NOERROR)
  317. {
  318. pslotTmp = (PSLOT) & plstslot->rgslot[ ((islot + cslot) *plstslot->cbSlot)-sizeof(SLOT)];
  319. pslot->cslot += pslotTmp->cslot;
  320. DecoupleSlot( plstslot, (islot + cslot), pslotTmp );
  321. }
  322. AddSlotToList( plstslot, islot, pslot );
  323. return S_OK ;
  324. }
  325. /////////////////////////////////////////////////////////////////////////////////////
  326. //
  327. // Initializes the Slot List object
  328. //
  329. // Did the initialization succeed
  330. // S_OK | method succeeded
  331. // E_OUTOFMEMORY | failed, out of memory
  332. //
  333. /////////////////////////////////////////////////////////////////////////////////////
  334. HRESULT InitializeSlotList( ULONG_PTR cslotMax, //IN max number of slots
  335. ULONG_PTR cbSlot, //IN slot size (row buffer size)
  336. ULONG_PTR cbPage, //IN page size
  337. LPBITARRAY pbits, //IN
  338. PLSTSLOT* pplstslot, //OUT pointer to slot list
  339. BYTE** prgslot //OUT
  340. )
  341. {
  342. LONG_PTR cbReserve;
  343. BYTE * pbAlloc;
  344. ULONG_PTR cbCommitFirst;
  345. PLSTSLOT plstslot;
  346. ULONG_PTR cslot, islotFirst;
  347. PSLOT pslot;
  348. HRESULT hr = S_OK;
  349. if (cbPage == 0)
  350. {
  351. SYSTEM_INFO sysinfo;
  352. GetSystemInfo( &sysinfo );
  353. cbPage = sysinfo.dwPageSize;
  354. }
  355. // Add in the LSTSLOT and SLOT
  356. cbSlot = cbSlot + (sizeof( LSTSLOT ) + sizeof( SLOT ));
  357. cbReserve = ((cslotMax *(cbSlot + (sizeof( LSTSLOT ) + sizeof( SLOT )))) / cbPage + 1) *cbPage;
  358. pbAlloc = (BYTE *) VirtualAlloc( NULL, cbReserve, MEM_RESERVE, PAGE_READWRITE );
  359. if (pbAlloc == NULL)
  360. {
  361. hr = E_OUTOFMEMORY ;
  362. }
  363. else
  364. {
  365. cbCommitFirst = ((sizeof( LSTSLOT ) + sizeof( SLOT )) / cbPage + 1) * cbPage;
  366. plstslot = (PLSTSLOT) VirtualAlloc( pbAlloc, cbCommitFirst, MEM_COMMIT, PAGE_READWRITE );
  367. if (plstslot == NULL)
  368. {
  369. VirtualFree((VOID *) pbAlloc, 0, MEM_RELEASE );
  370. hr = E_OUTOFMEMORY ;
  371. }
  372. else
  373. {
  374. plstslot->cbSlot = cbSlot;
  375. plstslot->cbPage = cbPage;
  376. plstslot->cbCommitCurrent = cbCommitFirst;
  377. plstslot->cbCommitMax = cbReserve;
  378. plstslot->pbitsSlot = pbits;
  379. if (cbSlot <= 2*(sizeof( LSTSLOT ) + sizeof( SLOT )))
  380. {
  381. islotFirst = (sizeof( LSTSLOT ) + sizeof( SLOT )) / cbSlot + (((sizeof( LSTSLOT ) + sizeof( SLOT )) % cbSlot) ? 1 : 0);
  382. plstslot->cbExtra = 0;
  383. cslot = (ULONG_PTR) ((cbCommitFirst / cbSlot) - islotFirst);
  384. plstslot->cbslotLeftOver = cbCommitFirst - cbSlot * (cslot + islotFirst);
  385. }
  386. else
  387. {
  388. islotFirst = 1;
  389. plstslot->cbExtra = cbSlot - (sizeof( LSTSLOT ) + sizeof( SLOT ));
  390. cslot = (cbCommitFirst - (sizeof( LSTSLOT ) + sizeof( SLOT ))) / cbSlot;
  391. plstslot->cbslotLeftOver = cbCommitFirst - (sizeof( LSTSLOT ) + sizeof( SLOT )) - cslot*cbSlot;
  392. }
  393. plstslot->rgslot = ((BYTE *) plstslot - plstslot->cbExtra);
  394. if (cslot)
  395. {
  396. plstslot->islotFirst = islotFirst;
  397. pslot = (PSLOT) & plstslot->rgslot[(islotFirst *plstslot->cbSlot)-sizeof(SLOT)];
  398. pslot->cslot = cslot;
  399. pslot->islotNext = 0;
  400. pslot->islotPrev = 0;
  401. }
  402. else
  403. {
  404. plstslot->islotFirst = 0;
  405. }
  406. plstslot->islotMin = islotFirst;
  407. plstslot->islotMax = islotFirst + cslot - 1;
  408. plstslot->islotRov = plstslot->islotFirst;
  409. *pplstslot = plstslot;
  410. *prgslot = plstslot->rgslot;
  411. }
  412. }
  413. return hr ;
  414. }
  415. /////////////////////////////////////////////////////////////////////////////////////
  416. //
  417. // Restore slot list to newly-initiated state
  418. //
  419. //
  420. // S_OK | method succeeded
  421. //
  422. /////////////////////////////////////////////////////////////////////////////////////
  423. HRESULT ResetSlotList ( PLSTSLOT plstslot )
  424. {
  425. ULONG_PTR cslot;
  426. PSLOT pslot;
  427. cslot = (plstslot->islotMax >= plstslot->islotMin) ? (plstslot->islotMax - plstslot->islotMin + 1) : 0;
  428. if (cslot)
  429. {
  430. plstslot->islotFirst = plstslot->islotMin;
  431. pslot = (PSLOT) & plstslot->rgslot[(plstslot->islotFirst *plstslot->cbSlot)-sizeof(SLOT)];
  432. pslot->cslot = cslot;
  433. pslot->islotNext = 0;
  434. pslot->islotPrev = 0;
  435. }
  436. else
  437. {
  438. plstslot->islotFirst = 0;
  439. }
  440. plstslot->islotRov = plstslot->islotFirst;
  441. return S_OK ;
  442. }
  443. /////////////////////////////////////////////////////////////////////////////////////
  444. //
  445. // Free slot list's memory
  446. //
  447. //
  448. // S_OK | method succeeded
  449. //
  450. /////////////////////////////////////////////////////////////////////////////////////
  451. HRESULT ReleaseSlotList ( PLSTSLOT plstslot )
  452. {
  453. if (plstslot != NULL)
  454. {
  455. if (plstslot->cbCommitCurrent)
  456. {
  457. VirtualFree((VOID *) plstslot, plstslot->cbCommitCurrent, MEM_DECOMMIT );
  458. }
  459. VirtualFree((VOID *) plstslot, 0, MEM_RELEASE );
  460. }
  461. return S_OK ;
  462. }
  463. /////////////////////////////////////////////////////////////////////////////////////
  464. // gets the buffer address for the slot
  465. /////////////////////////////////////////////////////////////////////////////////////
  466. ROWBUFF* GetRowBuffer(PLSTSLOT plstslot , HSLOT islot)
  467. {
  468. BYTE *pTemp = & (plstslot->rgslot[(islot * plstslot->cbSlot)]);
  469. ROWBUFF * pBuff = (ROWBUFF *)&(plstslot->rgslot[(islot * plstslot->cbSlot)]);
  470. return pBuff;
  471. }
  472. /////////////////////////////////////////////////////////////////////////////////////////////
  473. //////////// CHashTbl Implementation /////////
  474. /////////////////////////////////////////////////////////////////////////////////////////////
  475. //-----------------------------------------------------------------------------------
  476. // CHashTbl::CHashTbl
  477. //
  478. // @mfunc CHashTbl constructor.
  479. //
  480. // @rdesc NONE
  481. //-----------------------------------------------------------------------------------
  482. CHashTbl::CHashTbl()
  483. {
  484. m_rgwHash = NULL;
  485. m_ulTableSize = 0;
  486. }
  487. //-----------------------------------------------------------------------------------
  488. // CHashTbl::~CHashTbl
  489. //
  490. // @mfunc CHashTbl destructor.
  491. //
  492. // @rdesc NONE
  493. //-----------------------------------------------------------------------------------
  494. CHashTbl::~CHashTbl()
  495. {
  496. if (m_rgwHash)
  497. g_pIMalloc->Free(m_rgwHash);
  498. }
  499. //////////////////////////////////////////////////////////////////////////////////////
  500. // CHashTbl::FInit
  501. //
  502. // Initialize the Hashtable object.
  503. //
  504. // Did the Initialization Succeed
  505. // TRUE Initialization succeeded
  506. // FALSE Initializtion failed
  507. //////////////////////////////////////////////////////////////////////////////////////
  508. BOOL CHashTbl::FInit(PLSTSLOT pLstSlot)
  509. {
  510. BOOL bRet = TRUE;
  511. // Initialize the hashtable size
  512. m_ulTableSize = HASHTBLSIZE;
  513. // Allocate the table.
  514. m_rgwHash = (USHORT*)g_pIMalloc->Alloc(m_ulTableSize*sizeof(USHORT));
  515. if (m_rgwHash == NULL)
  516. {
  517. bRet = FALSE;
  518. }
  519. else
  520. {
  521. memset(m_rgwHash, 0x00, m_ulTableSize*sizeof(USHORT)); // Initialize.
  522. m_pLstSlot = pLstSlot;
  523. }
  524. return bRet;
  525. }
  526. //////////////////////////////////////////////////////////////////////////////////////
  527. // CHashTbl::InsertFindBmk
  528. //
  529. // Either only check if a given bookmark is already in the hashtable
  530. // (fFindOnly = TRUE), or check, and if it is not there, insert.
  531. //
  532. // Returns one of the following values:
  533. // S_OK Bookmark found in the hashtable,
  534. // S_FALSE Bookmark not found, if fFindOnly = FALSE, the new row
  535. // with this bookmark was inserted in the table.
  536. //////////////////////////////////////////////////////////////////////////////////////
  537. STDMETHODIMP CHashTbl::InsertFindBmk
  538. (
  539. BOOL fFindOnly, //@parm IN | FindOnly or Find/Insert
  540. HSLOT iSlot, //@parm IN | handle of the rowbuffer to be inserted
  541. ULONG_PTR cbBmk, //@parm IN | bookmark length
  542. BYTE *pbBmk, //@parm IN | bookmark pointer
  543. ULONG_PTR *pirowSlotFound //@parm OUT | if bookmark found returns handle of the
  544. // row that contains the bookmark
  545. )
  546. {
  547. //NTRaid:111766
  548. // 06/07/00
  549. DBHASHVALUE BmkHash = 0;
  550. HROW iSlotCurr = 0;
  551. PROWBUFF prowbuffCur = NULL;
  552. HRESULT hr = S_FALSE;
  553. assert(cbBmk == BOOKMARKSIZE && pbBmk);
  554. assert(pirowSlotFound);
  555. // Hash the bookmark. The hash value indexes the hashtable element which, if
  556. // not empty, will contain the handle to the beginning of the list of rows whose
  557. // bookmarks hash to the same value.
  558. HashBmk(cbBmk, pbBmk, &BmkHash);
  559. assert(BmkHash <= m_ulTableSize);
  560. iSlotCurr = m_rgwHash[BmkHash];
  561. // If the entry is non-zero, search the corresponding list for this bookmark.
  562. if (iSlotCurr)
  563. {
  564. prowbuffCur = GetRowBuffer(m_pLstSlot,iSlotCurr);
  565. iSlotCurr = 0;
  566. // Walk the overflow list looking for bookmark match.
  567. while (prowbuffCur)
  568. {
  569. assert(prowbuffCur->dwBmk && "Error attempting to compare bookmark on invalid row");
  570. // Compare the bookmarks
  571. if (cbBmk == prowbuffCur->cbBmk && cbBmk == BOOKMARKSIZE &&
  572. memcmp(&(prowbuffCur->dwBmk), pbBmk , BOOKMARKSIZE) == 0)
  573. {
  574. iSlotCurr = prowbuffCur->ulSlot;
  575. break;
  576. }
  577. prowbuffCur = prowbuffCur->prowbuffNext;
  578. }
  579. }
  580. // No insertion in the hashtable is needed or necessary.
  581. if (fFindOnly || iSlotCurr)
  582. {
  583. *pirowSlotFound = iSlotCurr; // Return the index of the rowbuffer that has
  584. // this bookmark, or 0 if none.
  585. hr = iSlotCurr ? S_OK : S_FALSE;
  586. }
  587. else
  588. {
  589. // Get the pointer to the row to be inserted.
  590. prowbuffCur = GetRowBuffer(m_pLstSlot,iSlot);
  591. // Initialize the new node for the list.
  592. if (m_rgwHash[BmkHash])
  593. {
  594. prowbuffCur->prowbuffNext = GetRowBuffer(m_pLstSlot,(ULONG)MAKELONG(m_rgwHash[BmkHash], 0));
  595. }
  596. else
  597. {
  598. prowbuffCur->prowbuffNext = NULL;
  599. }
  600. prowbuffCur->wBmkHash = (USHORT)BmkHash;
  601. prowbuffCur->ulSlot = iSlot;
  602. // Always insert a new node at the beginning of the list.
  603. m_rgwHash[BmkHash] = LOWORD(iSlot);
  604. *pirowSlotFound = iSlot;
  605. }
  606. // S_FALSE signifies that originally there was no row with this bookmark
  607. // in the hashtable.
  608. return hr;
  609. }
  610. //////////////////////////////////////////////////////////////////////////////////////
  611. // CRowset::HashBmk
  612. //
  613. // Hashes a fixed-size bookmark for a table of given size.
  614. //
  615. // Returns one of the following values:
  616. // S_OK Hashing succeeded,
  617. // E_INVALIDARG Hashing failed because the bookmark was invalid
  618. // or the pointer to bookmark was NULL.
  619. //////////////////////////////////////////////////////////////////////////////////////
  620. STDMETHODIMP CHashTbl::HashBmk
  621. (
  622. DBBKMARK cbBmk,
  623. const BYTE *pbBmk,
  624. DBHASHVALUE *pdwHashedValue)
  625. {
  626. HRESULT hr = S_OK;
  627. if (cbBmk != BOOKMARKSIZE || pbBmk == NULL)
  628. {
  629. hr = E_INVALIDARG;
  630. }
  631. else
  632. {
  633. assert(pdwHashedValue);
  634. *pdwHashedValue = (*(UNALIGNED ULONG*)pbBmk) % m_ulTableSize;
  635. }
  636. return hr;
  637. }
  638. //////////////////////////////////////////////////////////////////////////////////////
  639. // CHashTbl::DeleteBmk
  640. //
  641. // Delete a bookmark corresponding to a given row from the hashtable.
  642. //
  643. // Returns one of the following values:
  644. // S_OK Bookmark was found and deleted from the hashtable,
  645. // S_FALSE Bookmark was not found in the hashtable.
  646. //////////////////////////////////////////////////////////////////////////////////////
  647. STDMETHODIMP CHashTbl::DeleteBmk
  648. (
  649. HSLOT ulSlot //@parm IN | handle of the rowbuffer with bookmark to be deleted.
  650. )
  651. {
  652. HSLOT iSlotCur;
  653. USHORT wBmkHash;
  654. HRESULT hr = S_OK;
  655. PROWBUFF * pprowbuffCur, prowbuffFirst;
  656. wBmkHash = GetRowBuffer(m_pLstSlot,ulSlot)->wBmkHash;
  657. iSlotCur = MAKELONG(m_rgwHash[wBmkHash], 0);
  658. //==============================================================
  659. // If there is a non-zero entry search the corresponding list.
  660. //==============================================================
  661. if (ulSlot)
  662. {
  663. pprowbuffCur = &prowbuffFirst;
  664. prowbuffFirst = GetRowBuffer(m_pLstSlot,iSlotCur);
  665. while (*pprowbuffCur)
  666. {
  667. //===========================================================
  668. // To delete a row under a given index just compare indices,
  669. // no need to look at bookmarks.
  670. //===========================================================
  671. if (ulSlot == (*pprowbuffCur)->ulSlot)
  672. {
  673. break;
  674. }
  675. pprowbuffCur = &(*pprowbuffCur)->prowbuffNext;
  676. }
  677. if (*pprowbuffCur == NULL)
  678. {
  679. hr = S_FALSE;
  680. }
  681. }
  682. else
  683. {
  684. hr = S_FALSE;
  685. }
  686. if(hr == S_OK)
  687. {
  688. // Remove the row from the list.
  689. if (pprowbuffCur == &prowbuffFirst)
  690. {
  691. m_rgwHash[wBmkHash] = (USHORT)((prowbuffFirst->prowbuffNext) ? (prowbuffFirst->prowbuffNext)->ulSlot : 0);
  692. }
  693. else
  694. {
  695. *pprowbuffCur = (*pprowbuffCur)->prowbuffNext;
  696. }
  697. }
  698. return hr;
  699. }