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.

TableScanCursor.java 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. Copyright (c) 2013 James Ahlborn
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with this library; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  14. USA
  15. */
  16. package com.healthmarketscience.jackcess.impl;
  17. import java.io.IOException;
  18. import com.healthmarketscience.jackcess.impl.TableImpl.RowState;
  19. /**
  20. * Simple un-indexed cursor.
  21. *
  22. * @author James Ahlborn
  23. */
  24. public class TableScanCursor extends CursorImpl
  25. {
  26. /** first position for the TableScanCursor */
  27. private static final ScanPosition FIRST_SCAN_POSITION =
  28. new ScanPosition(RowIdImpl.FIRST_ROW_ID);
  29. /** last position for the TableScanCursor */
  30. private static final ScanPosition LAST_SCAN_POSITION =
  31. new ScanPosition(RowIdImpl.LAST_ROW_ID);
  32. /** ScanDirHandler for forward traversal */
  33. private final ScanDirHandler _forwardDirHandler =
  34. new ForwardScanDirHandler();
  35. /** ScanDirHandler for backward traversal */
  36. private final ScanDirHandler _reverseDirHandler =
  37. new ReverseScanDirHandler();
  38. /** Cursor over the pages that this table owns */
  39. private final UsageMap.PageCursor _ownedPagesCursor;
  40. public TableScanCursor(TableImpl table) {
  41. super(new IdImpl(table, null), table,
  42. FIRST_SCAN_POSITION, LAST_SCAN_POSITION);
  43. _ownedPagesCursor = table.getOwnedPagesCursor();
  44. }
  45. @Override
  46. protected ScanDirHandler getDirHandler(boolean moveForward) {
  47. return (moveForward ? _forwardDirHandler : _reverseDirHandler);
  48. }
  49. @Override
  50. protected boolean isUpToDate() {
  51. return(super.isUpToDate() && _ownedPagesCursor.isUpToDate());
  52. }
  53. @Override
  54. protected void reset(boolean moveForward) {
  55. _ownedPagesCursor.reset(moveForward);
  56. super.reset(moveForward);
  57. }
  58. @Override
  59. protected void restorePositionImpl(PositionImpl curPos, PositionImpl prevPos)
  60. throws IOException
  61. {
  62. if(!(curPos instanceof ScanPosition) ||
  63. !(prevPos instanceof ScanPosition)) {
  64. throw new IllegalArgumentException(
  65. "Restored positions must be scan positions");
  66. }
  67. _ownedPagesCursor.restorePosition(curPos.getRowId().getPageNumber(),
  68. prevPos.getRowId().getPageNumber());
  69. super.restorePositionImpl(curPos, prevPos);
  70. }
  71. @Override
  72. protected PositionImpl getRowPosition(RowIdImpl rowId) throws IOException
  73. {
  74. return new ScanPosition(rowId);
  75. }
  76. @Override
  77. protected PositionImpl findAnotherPosition(
  78. RowState rowState, PositionImpl curPos, boolean moveForward)
  79. throws IOException
  80. {
  81. ScanDirHandler handler = getDirHandler(moveForward);
  82. // figure out how many rows are left on this page so we can find the
  83. // next row
  84. RowIdImpl curRowId = curPos.getRowId();
  85. TableImpl.positionAtRowHeader(rowState, curRowId);
  86. int currentRowNumber = curRowId.getRowNumber();
  87. // loop until we find the next valid row or run out of pages
  88. while(true) {
  89. currentRowNumber = handler.getAnotherRowNumber(currentRowNumber);
  90. curRowId = new RowIdImpl(curRowId.getPageNumber(), currentRowNumber);
  91. TableImpl.positionAtRowHeader(rowState, curRowId);
  92. if(!rowState.isValid()) {
  93. // load next page
  94. curRowId = new RowIdImpl(handler.getAnotherPageNumber(),
  95. RowIdImpl.INVALID_ROW_NUMBER);
  96. TableImpl.positionAtRowHeader(rowState, curRowId);
  97. if(!rowState.isHeaderPageNumberValid()) {
  98. //No more owned pages. No more rows.
  99. return handler.getEndPosition();
  100. }
  101. // update row count and initial row number
  102. currentRowNumber = handler.getInitialRowNumber(
  103. rowState.getRowsOnHeaderPage());
  104. } else if(!rowState.isDeleted()) {
  105. // we found a valid, non-deleted row, return it
  106. return new ScanPosition(curRowId);
  107. }
  108. }
  109. }
  110. /**
  111. * Handles moving the table scan cursor in a given direction. Separates
  112. * cursor logic from value storage.
  113. */
  114. private abstract class ScanDirHandler extends DirHandler {
  115. public abstract int getAnotherRowNumber(int curRowNumber);
  116. public abstract int getAnotherPageNumber();
  117. public abstract int getInitialRowNumber(int rowsOnPage);
  118. }
  119. /**
  120. * Handles moving the table scan cursor forward.
  121. */
  122. private final class ForwardScanDirHandler extends ScanDirHandler {
  123. @Override
  124. public PositionImpl getBeginningPosition() {
  125. return getFirstPosition();
  126. }
  127. @Override
  128. public PositionImpl getEndPosition() {
  129. return getLastPosition();
  130. }
  131. @Override
  132. public int getAnotherRowNumber(int curRowNumber) {
  133. return curRowNumber + 1;
  134. }
  135. @Override
  136. public int getAnotherPageNumber() {
  137. return _ownedPagesCursor.getNextPage();
  138. }
  139. @Override
  140. public int getInitialRowNumber(int rowsOnPage) {
  141. return -1;
  142. }
  143. }
  144. /**
  145. * Handles moving the table scan cursor backward.
  146. */
  147. private final class ReverseScanDirHandler extends ScanDirHandler {
  148. @Override
  149. public PositionImpl getBeginningPosition() {
  150. return getLastPosition();
  151. }
  152. @Override
  153. public PositionImpl getEndPosition() {
  154. return getFirstPosition();
  155. }
  156. @Override
  157. public int getAnotherRowNumber(int curRowNumber) {
  158. return curRowNumber - 1;
  159. }
  160. @Override
  161. public int getAnotherPageNumber() {
  162. return _ownedPagesCursor.getPreviousPage();
  163. }
  164. @Override
  165. public int getInitialRowNumber(int rowsOnPage) {
  166. return rowsOnPage;
  167. }
  168. }
  169. /**
  170. * Value object which maintains the current position of a TableScanCursor.
  171. */
  172. private static final class ScanPosition extends PositionImpl
  173. {
  174. private final RowIdImpl _rowId;
  175. private ScanPosition(RowIdImpl rowId) {
  176. _rowId = rowId;
  177. }
  178. @Override
  179. public RowIdImpl getRowId() {
  180. return _rowId;
  181. }
  182. @Override
  183. protected boolean equalsImpl(Object o) {
  184. return getRowId().equals(((ScanPosition)o).getRowId());
  185. }
  186. @Override
  187. public String toString() {
  188. return "RowId = " + getRowId();
  189. }
  190. }
  191. }