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.

542 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000.
  5. //
  6. // File: regtrans.cxx
  7. //
  8. // Contents: Watch Region Transformer
  9. //
  10. // Classes: CRegionTransformer
  11. //
  12. // History: 20-Jul-95 BartoszM Created
  13. //
  14. //--------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <seglist.hxx>
  18. #include <wregion.hxx>
  19. #include "tabledbg.hxx"
  20. #include "regtrans.hxx"
  21. #include "tblwindo.hxx"
  22. #include "tputget.hxx"
  23. BOOL CRegionTransformer::Validate()
  24. {
  25. tbDebugOut(( DEB_REGTRANS, "CRegionTransformer::Validate\n" ));
  26. DumpState();
  27. _iFetch = _iFetchBmk + _offFetch;
  28. if (_cFetch < 0)
  29. {
  30. // for negative row count, we swap the start
  31. // of the fetch region with its end
  32. _iFetch += _cFetch + 1;
  33. _cFetch = - _cFetch;
  34. }
  35. if (_pRegion != 0)
  36. {
  37. _cWatch = _pRegion->RowCount();
  38. if (_iFetch < _iWatch)
  39. {
  40. _isExtendBackward = TRUE;
  41. }
  42. if (_iFetch + _cFetch > _iWatch + _cWatch)
  43. {
  44. _isExtendForward = TRUE;
  45. }
  46. if ( !_pRegion->IsInit() )
  47. {
  48. //
  49. // BootStrap - creating a watch region for the first time.
  50. //
  51. _iWatchNew = _iFetch;
  52. _cWatchNew = _cFetch;
  53. _isContiguous = FALSE;
  54. return TRUE;
  55. }
  56. else if (_pRegion->Mode() & DBWATCHMODE_EXTEND)
  57. {
  58. return ValidateExtend();
  59. }
  60. else if (_pRegion->Mode() & DBWATCHMODE_MOVE)
  61. {
  62. return ValidateMove();
  63. }
  64. else
  65. {
  66. return FALSE;
  67. }
  68. }
  69. return TRUE;
  70. }
  71. BOOL CRegionTransformer::ValidateMove ()
  72. {
  73. tbDebugOut(( DEB_REGTRANS,
  74. "CRegionTransformer::ValidateMove\n" ));
  75. Win4Assert( 0 != _pRegion );
  76. if (_isExtendForward && _isExtendBackward)
  77. return FALSE;
  78. _cWatchNew = _cWatch;
  79. if (_isExtendForward)
  80. {
  81. _iWatchNew = _iFetch + _cFetch - _cWatchNew;
  82. }
  83. else
  84. {
  85. _iWatchNew = _iFetch;
  86. }
  87. // For the new region to be contiguous with the
  88. // old region we require that the fetch bookmark
  89. // be within the old region and that there be overlap
  90. // between the old and the new regions. In any other case
  91. // the client cannot be sure of contiguity and we are
  92. // free to skip any buckets between the two regions.
  93. // Is the Fetch Bookmark inside the watch region?
  94. if (_iFetchBmk >= _iWatch && _iFetchBmk < _iWatch + _cWatch)
  95. {
  96. // Do the regions overlap?
  97. if ( _isExtendBackward && _iWatchNew + _cWatchNew > _iWatch
  98. || !_isExtendBackward && _iWatchNew < _iWatch + _cWatch )
  99. {
  100. _isContiguous = TRUE;
  101. }
  102. }
  103. DumpState();
  104. if (!_isContiguous && _cFetch != _cWatchNew)
  105. return FALSE;
  106. // if ( !_isContiguous && _cFetch > _cWatchNew )
  107. // return FALSE;
  108. return TRUE;
  109. }
  110. BOOL CRegionTransformer::ValidateExtend ()
  111. {
  112. tbDebugOut(( DEB_REGTRANS,
  113. "CRegionTransformer::ValidateExtend\n" ));
  114. _iWatchNew = _iWatch;
  115. _cWatchNew = _cWatch;
  116. if (_isExtendBackward)
  117. {
  118. // is there a gap?
  119. if (_iFetch + _cFetch < _iWatch)
  120. return FALSE;
  121. _iWatchNew = _iFetch;
  122. _cWatchNew += _iWatch - _iFetch;
  123. }
  124. if (_isExtendForward)
  125. {
  126. // is there a gap?
  127. if (_iFetch > _iWatch + _cWatch)
  128. return FALSE;
  129. _cWatchNew += _iFetch + _cFetch - (_iWatch + _cWatch);
  130. }
  131. _isContiguous = TRUE;
  132. return TRUE;
  133. }
  134. void CRegionTransformer::Transform (CTableSegList& segList, CWatchList& watchList)
  135. {
  136. tbDebugOut(( DEB_REGTRANS, "++++++ CRegionTransformer::Transform - Entering \n" ));
  137. if (!_isContiguous)
  138. {
  139. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "Not Contiguous\n" ));
  140. // Delete old region, create new region
  141. watchList.ShrinkRegionToZero (_pRegion->Handle());
  142. watchList.BuildRegion ( _pRegion->Handle(),
  143. _pSegmentLowFetch,
  144. 0, // NEWFEATURE: no watch regions for chapters
  145. ((CTableWindow*)_pSegmentLowFetch)->GetBookMarkAt((ULONG)_offLowFetchInSegment),
  146. (LONG) _cWatchNew );
  147. return;
  148. }
  149. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME,
  150. " Chapter=0x%X \tBookMark=0x%X \tcRows=%d \tSegment=0x%X \n",
  151. _pRegion->Chapter(), _pRegion->Bookmark(),
  152. _pRegion->RowCount(), _pRegion->Segment() ));
  153. DumpState();
  154. Win4Assert( _iWatch >= 0 && _iWatchNew >= 0 );
  155. CTableSegment* pSegment;
  156. if (_isExtendBackward)
  157. {
  158. pSegment = _pSegmentLowFetch;
  159. }
  160. else
  161. {
  162. pSegment = _pRegion->Segment();
  163. }
  164. // Create a state machine that will transform
  165. // watch regions window by window
  166. CDoubleTableSegIter iter (pSegment);
  167. enum State
  168. {
  169. stStart, stInOld, stInNew, stInBoth, stEnd
  170. };
  171. State state = stStart;
  172. CTableWindow* pWindow = iter.GetWindow();
  173. DBROWCOUNT cRowsInWindow = pWindow->RowCount();
  174. BOOL isLast = segList.IsLast(iter);
  175. DBROWCOUNT offset = 0;
  176. DBROWCOUNT cWatchLeft = _cWatchNew;
  177. Win4Assert( _cWatchNew >= _cWatch );
  178. DBROWCOUNT iBeginInWindow = 0;
  179. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "Doing State Change\n" ));
  180. do
  181. {
  182. BOOL fAdvance = FALSE;
  183. switch (state)
  184. {
  185. case stStart:
  186. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "stStart\n" ));
  187. if (HasNewRegion( offset, cRowsInWindow))
  188. {
  189. iBeginInWindow = _iWatchNew - offset;
  190. // NEWFEATURE no watches for chaptered tables
  191. _pRegion->Set (0, pWindow->GetBookMarkAt((ULONG) iBeginInWindow), (LONG) _cWatchNew);
  192. _pRegion->SetSegment (pWindow);
  193. //Win4Assert( pWindow->HasWatch( _pRegion->Handle() ) );
  194. state = stInNew;
  195. }
  196. if (HasOldRegion( (long) offset, (long) cRowsInWindow))
  197. {
  198. if (state == stInNew)
  199. state = stInBoth;
  200. else
  201. state = stInOld;
  202. }
  203. break;
  204. case stInOld:
  205. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "stInOld\n" ));
  206. if (HasNewRegion( offset, cRowsInWindow))
  207. {
  208. iBeginInWindow = _iWatchNew - offset;
  209. // NEWFEATURE no watches for chaptered tables
  210. _pRegion->Set (0, pWindow->GetBookMarkAt((ULONG)iBeginInWindow), (LONG)_cWatchNew);
  211. _pRegion->SetSegment (pWindow);
  212. Win4Assert( pWindow->HasWatch( _pRegion->Handle() ) );
  213. state = stInBoth;
  214. }
  215. else if (HasEndOldRegion(offset, cRowsInWindow))
  216. {
  217. pWindow->DeleteWatch (_pRegion->Handle());
  218. state = stEnd;
  219. }
  220. else
  221. {
  222. pWindow->DeleteWatch (_pRegion->Handle());
  223. fAdvance = !isLast;
  224. }
  225. break;
  226. case stInNew:
  227. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "stInNew\n" ));
  228. if (HasOldRegion(offset, cRowsInWindow))
  229. {
  230. state = stInBoth;
  231. }
  232. else if (HasEndNewRegion(offset, cRowsInWindow))
  233. {
  234. cWatchLeft -= pWindow->AddWatch (
  235. _pRegion->Handle(),
  236. (LONG) iBeginInWindow,
  237. (LONG) cWatchLeft,
  238. isLast );
  239. // in all subsequent windows the watch
  240. // will start at offset zero
  241. iBeginInWindow = 0;
  242. state = stEnd;
  243. }
  244. else
  245. {
  246. Win4Assert( cWatchLeft > 0 );
  247. cWatchLeft -= pWindow->AddWatch (
  248. _pRegion->Handle(),
  249. (LONG) iBeginInWindow,
  250. (LONG) cWatchLeft,
  251. isLast );
  252. // in all subsequent windows the watch
  253. // will start at offset zero
  254. iBeginInWindow = 0;
  255. fAdvance = !isLast;
  256. }
  257. break;
  258. case stInBoth:
  259. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME, "stInBoth\n" ));
  260. cWatchLeft -= pWindow->ModifyWatch (
  261. _pRegion->Handle(),
  262. (LONG) iBeginInWindow,
  263. (LONG) cWatchLeft,
  264. isLast );
  265. if ( !isLast )
  266. {
  267. // in all subsequent windows the watch
  268. // will start at offset zero
  269. iBeginInWindow = 0;
  270. fAdvance = TRUE;
  271. if (HasEndNewRegion(offset, cRowsInWindow))
  272. {
  273. state = stInOld;
  274. }
  275. else
  276. {
  277. Win4Assert( cWatchLeft > 0 || isLast );
  278. }
  279. if (HasEndOldRegion(offset, cRowsInWindow))
  280. {
  281. if (state == stInOld)
  282. {
  283. fAdvance = FALSE;
  284. state = stEnd;
  285. }
  286. else
  287. {
  288. state = stInNew;
  289. }
  290. }
  291. }
  292. else
  293. {
  294. state = stEnd;
  295. }
  296. break;
  297. case stEnd:
  298. break;
  299. }
  300. if ( fAdvance)
  301. {
  302. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME,
  303. "--- BEFORE ADVANCING offset=%d cRowsInWindow=%d isLast=%d\n",
  304. offset, cRowsInWindow, isLast ));
  305. Win4Assert (!isLast);
  306. offset += cRowsInWindow;
  307. segList.Advance(iter);
  308. Win4Assert( iter.GetSegment()->IsWindow() );
  309. pWindow = iter.GetWindow();
  310. cRowsInWindow = pWindow->RowCount();
  311. isLast = segList.IsLast(iter);
  312. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME,
  313. "--- AFTER ADVANCING offset=%d cRowsInWindow=%d isLast=%d\n",
  314. offset, cRowsInWindow, isLast ));
  315. }
  316. } while ( state != stEnd && !segList.AtEnd(iter) );
  317. tbDebugOut(( DEB_REGTRANS, "------ CRegionTransformer::Transform - Leaving \n" ));
  318. tbDebugOut(( DEB_REGTRANS | DEB_NOCOMPNAME,
  319. " Chapter=0x%X \tBookMark=0x%X \tcRows=%d \tSegment=0x%X \n",
  320. _pRegion->Chapter(), _pRegion->Bookmark(),
  321. _pRegion->RowCount(), _pRegion->Segment() ));
  322. DumpState();
  323. }
  324. //+---------------------------------------------------------------------------
  325. //
  326. // Function: MoveOrigin
  327. //
  328. // Synopsis: The co-ordinate origin is WRT to the lower of the two:
  329. // a. Watch Segment
  330. // b. The "anchor" segment.
  331. //
  332. // When the "fetch" segment is before this origin, then some of
  333. // the co-ordinates like the _iWatchNew and _iFetch will be < 0.
  334. // In-order to have all our co-ordinates always postive, we will
  335. // the origin to the "fetch" segment.
  336. //
  337. // Arguments: [cDelta] - The number of rows to move the origin by.
  338. // This MUST be -ve.
  339. //
  340. // History: 9-05-95 srikants Created
  341. //
  342. // Notes:
  343. //
  344. //----------------------------------------------------------------------------
  345. void CRegionTransformer::MoveOrigin( DBROWCOUNT cDelta )
  346. {
  347. Win4Assert( cDelta < 0 );
  348. Win4Assert( _iFetch < 0 );
  349. Win4Assert( _iWatchNew < 0 );
  350. cDelta = -cDelta;
  351. Win4Assert( cDelta >= -_iFetch );
  352. _iWatchNew += cDelta;
  353. _iWatch += cDelta;
  354. _iFetch += cDelta;
  355. Win4Assert( _iWatchNew >= 0 && _iWatch >= 0 && _iFetch >= 0 );
  356. }
  357. //+---------------------------------------------------------------------------
  358. //
  359. // Member: CRegionTransformer::DecrementFetchCount
  360. //
  361. // Synopsis:
  362. //
  363. // Arguments: [rowLocator] -
  364. // [iter] -
  365. // [list] -
  366. //
  367. // Returns:
  368. //
  369. // Modifies:
  370. //
  371. // History: 7-26-95 srikants Created
  372. //
  373. // Notes:
  374. //
  375. //----------------------------------------------------------------------------
  376. void CRegionTransformer::DecrementFetchCount( CTableRowLocator & rowLocator,
  377. CFwdTableSegIter & iter,
  378. CTableSegList & list )
  379. {
  380. Win4Assert( list.AtEnd(iter) );
  381. DBROWCOUNT cDiff = rowLocator.GetBeyondTableCount();
  382. tbDebugOut(( DEB_REGTRANS,
  383. "CRegionTransformer::DecrementFetchCount - cDiff %d\n", cDiff ));
  384. if ( (_cFetch <= 0 && cDiff <= 0) || (_cFetch >= 0 && cDiff >= 0) )
  385. {
  386. tbDebugOut(( DEB_REGTRANS, "Beyond End of Table\n" ));
  387. _cFetch = 0;
  388. }
  389. else if ( _cFetch < 0 )
  390. {
  391. //
  392. // We are doing a reverse retrieval of rows. We must decrease the
  393. // number of rows to be retrieved by the amount we overshot.
  394. //
  395. Win4Assert( cDiff > 0 );
  396. _cFetch += cDiff;
  397. if ( _cFetch >= 0 )
  398. {
  399. _cFetch = 0;
  400. _cWatchNew = 0;
  401. }
  402. else
  403. {
  404. Win4Assert( _cWatchNew >= _cFetch );
  405. Win4Assert( !"The logic here is not clear. Check it properly" );
  406. rowLocator.SeekAndSetFetchBmk( WORKID_TBLLAST, iter );
  407. DBROWCOUNT iOffset = (DBROWCOUNT) iter.GetSegment()->RowCount();
  408. if ( iOffset > 0 )
  409. {
  410. iOffset--;
  411. }
  412. _iFetch = iOffset;
  413. }
  414. }
  415. else
  416. {
  417. Win4Assert( cDiff < 0 );
  418. Win4Assert( !IsWatched() || _iWatchNew <= 0 );
  419. _cFetch += cDiff;
  420. _iWatchNew = 0;
  421. if ( _cFetch <= 0 )
  422. {
  423. _cFetch = 0;
  424. _cWatchNew = 0;
  425. }
  426. else
  427. {
  428. Win4Assert( !IsWatched() || _cWatchNew >= _cFetch );
  429. rowLocator.SeekAndSetFetchBmk( WORKID_TBLFIRST, iter );
  430. }
  431. }
  432. return;
  433. }