1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.healthmarketscience.jackcess.impl;
18
19 import java.io.IOException;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Iterator;
23 import java.util.Map;
24 import java.util.NoSuchElementException;
25 import java.util.function.Predicate;
26
27 import com.healthmarketscience.jackcess.Column;
28 import com.healthmarketscience.jackcess.Cursor;
29 import com.healthmarketscience.jackcess.CursorBuilder;
30 import com.healthmarketscience.jackcess.Row;
31 import com.healthmarketscience.jackcess.RowId;
32 import com.healthmarketscience.jackcess.RuntimeIOException;
33 import com.healthmarketscience.jackcess.impl.TableImpl.RowState;
34 import com.healthmarketscience.jackcess.util.ColumnMatcher;
35 import com.healthmarketscience.jackcess.util.ErrorHandler;
36 import com.healthmarketscience.jackcess.util.IterableBuilder;
37 import com.healthmarketscience.jackcess.util.SimpleColumnMatcher;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public abstract class CursorImpl implements Cursor
58 {
59 private static final Log LOG = LogFactory.getLog(CursorImpl.class);
60
61
62 public static final boolean MOVE_FORWARD = true;
63
64 public static final boolean MOVE_REVERSE = false;
65
66
67 private final IdImpl _id;
68
69 private final TableImpl _table;
70
71 private final RowState _rowState;
72
73 private final PositionImpl _firstPos;
74
75 private final PositionImpl _lastPos;
76
77 protected PositionImpl _prevPos;
78
79 protected PositionImpl _curPos;
80
81 protected ColumnMatcher _columnMatcher = SimpleColumnMatcher.INSTANCE;
82
83 protected CursorImpl(IdImpl id, TableImpl table, PositionImpl firstPos,
84 PositionImpl lastPos) {
85 _id = id;
86 _table = table;
87 _rowState = _table.createRowState();
88 _firstPos = firstPos;
89 _lastPos = lastPos;
90 _curPos = firstPos;
91 _prevPos = firstPos;
92 }
93
94
95
96
97
98 public static CursorImpl createCursor(TableImpl table) {
99 return new TableScanCursor(table);
100 }
101
102 public RowState getRowState() {
103 return _rowState;
104 }
105
106 @Override
107 public IdImpl getId() {
108 return _id;
109 }
110
111 @Override
112 public TableImpl getTable() {
113 return _table;
114 }
115
116 public JetFormat getFormat() {
117 return getTable().getFormat();
118 }
119
120 public PageChannel getPageChannel() {
121 return getTable().getPageChannel();
122 }
123
124 @Override
125 public ErrorHandler getErrorHandler() {
126 return _rowState.getErrorHandler();
127 }
128
129 @Override
130 public void setErrorHandler(ErrorHandler newErrorHandler) {
131 _rowState.setErrorHandler(newErrorHandler);
132 }
133
134 @Override
135 public ColumnMatcher getColumnMatcher() {
136 return _columnMatcher;
137 }
138
139 @Override
140 public void setColumnMatcher(ColumnMatcher columnMatcher) {
141 if(columnMatcher == null) {
142 columnMatcher = getDefaultColumnMatcher();
143 }
144 _columnMatcher = columnMatcher;
145 }
146
147
148
149
150 protected ColumnMatcher getDefaultColumnMatcher() {
151 return SimpleColumnMatcher.INSTANCE;
152 }
153
154 @Override
155 public SavepointImpl getSavepoint() {
156 return new SavepointImpl(_id, _curPos, _prevPos);
157 }
158
159 @Override
160 public void restoreSavepoint(Savepoint savepoint)
161 throws IOException
162 {
163 restoreSavepoint((SavepointImpl)savepoint);
164 }
165
166 public void restoreSavepoint(SavepointImpl savepoint)
167 throws IOException
168 {
169 if(!_id.equals(savepoint.getCursorId())) {
170 throw new IllegalArgumentException(
171 "Savepoint " + savepoint + " is not valid for this cursor with id "
172 + _id);
173 }
174 restorePosition(savepoint.getCurrentPosition(),
175 savepoint.getPreviousPosition());
176 }
177
178
179
180
181 protected PositionImpl getFirstPosition() {
182 return _firstPos;
183 }
184
185
186
187
188 protected PositionImpl getLastPosition() {
189 return _lastPos;
190 }
191
192 @Override
193 public void reset() {
194 beforeFirst();
195 }
196
197 @Override
198 public void beforeFirst() {
199 reset(MOVE_FORWARD);
200 }
201
202 @Override
203 public void afterLast() {
204 reset(MOVE_REVERSE);
205 }
206
207 @Override
208 public boolean isBeforeFirst() throws IOException {
209 return isAtBeginning(MOVE_FORWARD);
210 }
211
212 @Override
213 public boolean isAfterLast() throws IOException {
214 return isAtBeginning(MOVE_REVERSE);
215 }
216
217 protected boolean isAtBeginning(boolean moveForward) throws IOException {
218 if(getDirHandler(moveForward).getBeginningPosition().equals(_curPos)) {
219 return !recheckPosition(!moveForward);
220 }
221 return false;
222 }
223
224 @Override
225 public boolean isCurrentRowDeleted() throws IOException
226 {
227
228
229 TableImpl.positionAtRowData(_rowState, _curPos.getRowId());
230 return _rowState.isDeleted();
231 }
232
233
234
235
236 protected void reset(boolean moveForward) {
237 _curPos = getDirHandler(moveForward).getBeginningPosition();
238 _prevPos = _curPos;
239 _rowState.reset();
240 }
241
242 @Override
243 public Iterator<Row> iterator() {
244 return new RowIterator(null, true, MOVE_FORWARD);
245 }
246
247 @Override
248 public IterableBuilder newIterable() {
249 return new IterableBuilder(this);
250 }
251
252 public Iterator<Row> iterator(IterableBuilder iterBuilder) {
253
254 switch(iterBuilder.getType()) {
255 case SIMPLE:
256 return new RowIterator(iterBuilder.getColumnNames(),
257 iterBuilder.isReset(), iterBuilder.isForward());
258 case COLUMN_MATCH: {
259 @SuppressWarnings("unchecked")
260 Map.Entry<Column,Object> matchPattern = (Map.Entry<Column,Object>)
261 iterBuilder.getMatchPattern();
262 return new ColumnMatchIterator(
263 iterBuilder.getColumnNames(), (ColumnImpl)matchPattern.getKey(),
264 matchPattern.getValue(), iterBuilder.isReset(),
265 iterBuilder.isForward(), iterBuilder.getColumnMatcher());
266 }
267 case ROW_MATCH: {
268 @SuppressWarnings("unchecked")
269 Map<String,?> matchPattern = (Map<String,?>)
270 iterBuilder.getMatchPattern();
271 return new RowMatchIterator(
272 iterBuilder.getColumnNames(), matchPattern,iterBuilder.isReset(),
273 iterBuilder.isForward(), iterBuilder.getColumnMatcher());
274 }
275 default:
276 throw new RuntimeException("unknown match type " + iterBuilder.getType());
277 }
278 }
279
280 @Override
281 public void deleteCurrentRow() throws IOException {
282 _table.deleteRow(_rowState, _curPos.getRowId());
283 }
284
285 @Override
286 public Object[] updateCurrentRow(Object... row) throws IOException {
287 return _table.updateRow(_rowState, _curPos.getRowId(), row);
288 }
289
290 @Override
291 public <M extends Map<String,Object>> M updateCurrentRowFromMap(M row)
292 throws IOException
293 {
294 return _table.updateRowFromMap(_rowState, _curPos.getRowId(), row);
295 }
296
297 @Override
298 public Row getNextRow() throws IOException {
299 return getNextRow(null);
300 }
301
302 @Override
303 public Row getNextRow(Collection<String> columnNames)
304 throws IOException
305 {
306 return getAnotherRow(columnNames, MOVE_FORWARD);
307 }
308
309 @Override
310 public Row getPreviousRow() throws IOException {
311 return getPreviousRow(null);
312 }
313
314 @Override
315 public Row getPreviousRow(Collection<String> columnNames)
316 throws IOException
317 {
318 return getAnotherRow(columnNames, MOVE_REVERSE);
319 }
320
321
322
323
324
325
326
327
328
329
330 private Row getAnotherRow(Collection<String> columnNames,
331 boolean moveForward)
332 throws IOException
333 {
334 if(moveToAnotherRow(moveForward)) {
335 return getCurrentRow(columnNames);
336 }
337 return null;
338 }
339
340 @Override
341 public boolean moveToNextRow() throws IOException
342 {
343 return moveToAnotherRow(MOVE_FORWARD);
344 }
345
346 @Override
347 public boolean moveToPreviousRow() throws IOException
348 {
349 return moveToAnotherRow(MOVE_REVERSE);
350 }
351
352
353
354
355
356
357 protected boolean moveToAnotherRow(boolean moveForward)
358 throws IOException
359 {
360 if(_curPos.equals(getDirHandler(moveForward).getEndPosition())) {
361
362 return recheckPosition(moveForward);
363 }
364
365 return moveToAnotherRowImpl(moveForward);
366 }
367
368
369
370
371
372 protected void restorePosition(PositionImpl curPos)
373 throws IOException
374 {
375 restorePosition(curPos, _curPos);
376 }
377
378
379
380
381
382 protected final void restorePosition(PositionImpl curPos,
383 PositionImpl prevPos)
384 throws IOException
385 {
386 if(!curPos.equals(_curPos) || !prevPos.equals(_prevPos)) {
387 restorePositionImpl(curPos, prevPos);
388 }
389 }
390
391
392
393
394 protected void restorePositionImpl(PositionImpl curPos, PositionImpl prevPos)
395 throws IOException
396 {
397
398 _prevPos = _curPos;
399 _curPos = curPos;
400 _rowState.reset();
401 }
402
403
404
405
406
407
408
409 private boolean recheckPosition(boolean moveForward)
410 throws IOException
411 {
412 if(isUpToDate()) {
413
414 return false;
415 }
416
417
418 restorePosition(_prevPos);
419 return moveToAnotherRowImpl(moveForward);
420 }
421
422
423
424
425
426 private boolean moveToAnotherRowImpl(boolean moveForward)
427 throws IOException
428 {
429 _rowState.reset();
430 _prevPos = _curPos;
431 _curPos = findAnotherPosition(_rowState, _curPos, moveForward);
432 TableImpl.positionAtRowHeader(_rowState, _curPos.getRowId());
433 return(!_curPos.equals(getDirHandler(moveForward).getEndPosition()));
434 }
435
436 @Override
437 public boolean findRow(RowId rowId) throws IOException
438 {
439 RowIdImpl../../com/healthmarketscience/jackcess/impl/RowIdImpl.html#RowIdImpl">RowIdImpl rowIdImpl = (RowIdImpl)rowId;
440 PositionImpl curPos = _curPos;
441 PositionImpl prevPos = _prevPos;
442 boolean found = false;
443 try {
444 reset(MOVE_FORWARD);
445 if(TableImpl.positionAtRowHeader(_rowState, rowIdImpl) == null) {
446 return false;
447 }
448 restorePosition(getRowPosition(rowIdImpl));
449 if(!isCurrentRowValid()) {
450 return false;
451 }
452 found = true;
453 return true;
454 } finally {
455 if(!found) {
456 try {
457 restorePosition(curPos, prevPos);
458 } catch(IOException e) {
459 LOG.error("Failed restoring position", e);
460 }
461 }
462 }
463 }
464
465 @Override
466 public boolean findFirstRow(Column columnPattern, Object valuePattern)
467 throws IOException
468 {
469 return findFirstRow((ColumnImpl)columnPattern, valuePattern);
470 }
471
472 public boolean findFirstRow(ColumnImpl columnPattern, Object valuePattern)
473 throws IOException
474 {
475 return findAnotherRow(columnPattern, valuePattern, true, MOVE_FORWARD,
476 _columnMatcher,
477 prepareSearchInfo(columnPattern, valuePattern));
478 }
479
480 @Override
481 public boolean findNextRow(Column columnPattern, Object valuePattern)
482 throws IOException
483 {
484 return findNextRow((ColumnImpl)columnPattern, valuePattern);
485 }
486
487 public boolean findNextRow(ColumnImpl columnPattern, Object valuePattern)
488 throws IOException
489 {
490 return findAnotherRow(columnPattern, valuePattern, false, MOVE_FORWARD,
491 _columnMatcher,
492 prepareSearchInfo(columnPattern, valuePattern));
493 }
494
495 protected boolean findAnotherRow(ColumnImpl columnPattern, Object valuePattern,
496 boolean reset, boolean moveForward,
497 ColumnMatcher columnMatcher, Object searchInfo)
498 throws IOException
499 {
500 PositionImpl curPos = _curPos;
501 PositionImpl prevPos = _prevPos;
502 boolean found = false;
503 try {
504 if(reset) {
505 reset(moveForward);
506 }
507 found = findAnotherRowImpl(columnPattern, valuePattern, moveForward,
508 columnMatcher, searchInfo);
509 return found;
510 } finally {
511 if(!found) {
512 try {
513 restorePosition(curPos, prevPos);
514 } catch(IOException e) {
515 LOG.error("Failed restoring position", e);
516 }
517 }
518 }
519 }
520
521 @Override
522 public boolean findFirstRow(Map<String,?> rowPattern) throws IOException
523 {
524 return findAnotherRow(rowPattern, true, MOVE_FORWARD, _columnMatcher,
525 prepareSearchInfo(rowPattern));
526 }
527
528 @Override
529 public boolean findNextRow(Map<String,?> rowPattern)
530 throws IOException
531 {
532 return findAnotherRow(rowPattern, false, MOVE_FORWARD, _columnMatcher,
533 prepareSearchInfo(rowPattern));
534 }
535
536 protected boolean findAnotherRow(Map<String,?> rowPattern, boolean reset,
537 boolean moveForward,
538 ColumnMatcher columnMatcher, Object searchInfo)
539 throws IOException
540 {
541 PositionImpl curPos = _curPos;
542 PositionImpl prevPos = _prevPos;
543 boolean found = false;
544 try {
545 if(reset) {
546 reset(moveForward);
547 }
548 found = findAnotherRowImpl(rowPattern, moveForward, columnMatcher,
549 searchInfo);
550 return found;
551 } finally {
552 if(!found) {
553 try {
554 restorePosition(curPos, prevPos);
555 } catch(IOException e) {
556 LOG.error("Failed restoring position", e);
557 }
558 }
559 }
560 }
561
562 @Override
563 public boolean currentRowMatches(Column columnPattern, Object valuePattern)
564 throws IOException
565 {
566 return currentRowMatches((ColumnImpl)columnPattern, valuePattern);
567 }
568
569 public boolean currentRowMatches(ColumnImpl columnPattern, Object valuePattern)
570 throws IOException
571 {
572 return currentRowMatchesImpl(columnPattern, valuePattern, _columnMatcher);
573 }
574
575 protected boolean currentRowMatchesImpl(ColumnImpl columnPattern,
576 Object valuePattern,
577 ColumnMatcher columnMatcher)
578 throws IOException
579 {
580 return currentRowMatchesPattern(
581 columnPattern.getName(), valuePattern, columnMatcher,
582 getCurrentRowValue(columnPattern));
583 }
584
585 @Override
586 public boolean currentRowMatches(Map<String,?> rowPattern)
587 throws IOException
588 {
589 return currentRowMatchesImpl(rowPattern, _columnMatcher);
590 }
591
592 protected boolean currentRowMatchesImpl(Map<String,?> rowPattern,
593 ColumnMatcher columnMatcher)
594 throws IOException
595 {
596 Row row = getCurrentRow(rowPattern.keySet());
597
598 if(rowPattern.size() != row.size()) {
599 return false;
600 }
601
602 for(Map.Entry<String,Object> e : row.entrySet()) {
603 String columnName = e.getKey();
604 if(!currentRowMatchesPattern(columnName, rowPattern.get(columnName),
605 columnMatcher, e.getValue())) {
606 return false;
607 }
608 }
609
610 return true;
611 }
612
613 @SuppressWarnings("unchecked")
614 protected final boolean currentRowMatchesPattern(
615 String columnPattern, Object valuePattern,
616 ColumnMatcher columnMatcher, Object rowValue) {
617
618 if(valuePattern instanceof Predicate<?>) {
619 return ((Predicate<Object>)valuePattern).test(rowValue);
620 }
621
622 return columnMatcher.matches(getTable(), columnPattern, valuePattern,
623 rowValue);
624 }
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639 protected boolean findAnotherRowImpl(
640 ColumnImpl columnPattern, Object valuePattern, boolean moveForward,
641 ColumnMatcher columnMatcher, Object searchInfo)
642 throws IOException
643 {
644 while(moveToAnotherRow(moveForward)) {
645 if(currentRowMatchesImpl(columnPattern, valuePattern, columnMatcher)) {
646 return true;
647 }
648 if(!keepSearching(columnMatcher, searchInfo)) {
649 break;
650 }
651 }
652 return false;
653 }
654
655
656
657
658
659
660
661
662
663
664
665
666 protected boolean findAnotherRowImpl(Map<String,?> rowPattern,
667 boolean moveForward,
668 ColumnMatcher columnMatcher,
669 Object searchInfo)
670 throws IOException
671 {
672 while(moveToAnotherRow(moveForward)) {
673 if(currentRowMatchesImpl(rowPattern, columnMatcher)) {
674 return true;
675 }
676 if(!keepSearching(columnMatcher, searchInfo)) {
677 break;
678 }
679 }
680 return false;
681 }
682
683
684
685
686
687 protected Object prepareSearchInfo(ColumnImpl columnPattern, Object valuePattern)
688 {
689 return null;
690 }
691
692
693
694
695
696 protected Object prepareSearchInfo(Map<String,?> rowPattern)
697 {
698 return null;
699 }
700
701
702
703
704
705 protected boolean keepSearching(ColumnMatcher columnMatcher,
706 Object searchInfo)
707 throws IOException
708 {
709 return true;
710 }
711
712 @Override
713 public int moveNextRows(int numRows) throws IOException
714 {
715 return moveSomeRows(numRows, MOVE_FORWARD);
716 }
717
718 @Override
719 public int movePreviousRows(int numRows) throws IOException
720 {
721 return moveSomeRows(numRows, MOVE_REVERSE);
722 }
723
724
725
726
727
728
729 private int moveSomeRows(int numRows, boolean moveForward)
730 throws IOException
731 {
732 int numMovedRows = 0;
733 while((numMovedRows < numRows) && moveToAnotherRow(moveForward)) {
734 ++numMovedRows;
735 }
736 return numMovedRows;
737 }
738
739 @Override
740 public Row getCurrentRow() throws IOException
741 {
742 return getCurrentRow(null);
743 }
744
745 @Override
746 public Row getCurrentRow(Collection<String> columnNames)
747 throws IOException
748 {
749 return _table.getRow(_rowState, _curPos.getRowId(), columnNames);
750 }
751
752 @Override
753 public Object getCurrentRowValue(Column column)
754 throws IOException
755 {
756 return getCurrentRowValue((ColumnImpl)column);
757 }
758
759 public Object getCurrentRowValue(ColumnImpl column)
760 throws IOException
761 {
762 return _table.getRowValue(_rowState, _curPos.getRowId(), column);
763 }
764
765 @Override
766 public void setCurrentRowValue(Column column, Object value)
767 throws IOException
768 {
769 setCurrentRowValue((ColumnImpl)column, value);
770 }
771
772 public void setCurrentRowValue(ColumnImpl column, Object value)
773 throws IOException
774 {
775 Object[] row = new Object[_table.getColumnCount()];
776 Arrays.fill(row, Column.KEEP_VALUE);
777 column.setRowValue(row, value);
778 _table.updateRow(_rowState, _curPos.getRowId(), row);
779 }
780
781
782
783
784
785 protected boolean isUpToDate() {
786 return _rowState.isUpToDate();
787 }
788
789
790
791
792 protected boolean isCurrentRowValid() throws IOException {
793 return(_curPos.getRowId().isValid() && !isCurrentRowDeleted() &&
794 !isBeforeFirst() && !isAfterLast());
795 }
796
797 @Override
798 public String toString() {
799 return getClass().getSimpleName() + " CurPosition " + _curPos +
800 ", PrevPosition " + _prevPos;
801 }
802
803
804
805
806
807 protected abstract PositionImpl getRowPosition(RowIdImpl rowId)
808 throws IOException;
809
810
811
812
813
814
815
816
817 protected abstract PositionImpl findAnotherPosition(RowState rowState,
818 PositionImpl curPos,
819 boolean moveForward)
820 throws IOException;
821
822
823
824
825 protected abstract DirHandler getDirHandler(boolean moveForward);
826
827
828
829
830
831 protected abstract class BaseIterator implements Iterator<Row>
832 {
833 protected final Collection<String> _columnNames;
834 protected final boolean _moveForward;
835 protected final ColumnMatcher _colMatcher;
836 protected Boolean _hasNext;
837 protected boolean _validRow;
838
839 protected BaseIterator(Collection<String> columnNames,
840 boolean reset, boolean moveForward,
841 ColumnMatcher columnMatcher)
842 {
843 _columnNames = columnNames;
844 _moveForward = moveForward;
845 _colMatcher = ((columnMatcher != null) ? columnMatcher : _columnMatcher);
846 try {
847 if(reset) {
848 reset(_moveForward);
849 } else if(isCurrentRowValid()) {
850 _hasNext = _validRow = true;
851 }
852 } catch(IOException e) {
853 throw new RuntimeIOException(e);
854 }
855 }
856
857 @Override
858 public boolean hasNext() {
859 if(_hasNext == null) {
860 try {
861 _hasNext = findNext();
862 _validRow = _hasNext;
863 } catch(IOException e) {
864 throw new RuntimeIOException(e);
865 }
866 }
867 return _hasNext;
868 }
869
870 @Override
871 public Row next() {
872 if(!hasNext()) {
873 throw new NoSuchElementException();
874 }
875 try {
876 Row rtn = getCurrentRow(_columnNames);
877 _hasNext = null;
878 return rtn;
879 } catch(IOException e) {
880 throw new RuntimeIOException(e);
881 }
882 }
883
884 @Override
885 public void remove() {
886 if(_validRow) {
887 try {
888 deleteCurrentRow();
889 _validRow = false;
890 } catch(IOException e) {
891 throw new RuntimeIOException(e);
892 }
893 } else {
894 throw new IllegalStateException("Not at valid row");
895 }
896 }
897
898 protected abstract boolean findNext() throws IOException;
899 }
900
901
902
903
904
905 private final class RowIterator extends BaseIterator
906 {
907 private RowIterator(Collection<String> columnNames, boolean reset,
908 boolean moveForward)
909 {
910 super(columnNames, reset, moveForward, null);
911 }
912
913 @Override
914 protected boolean findNext() throws IOException {
915 return moveToAnotherRow(_moveForward);
916 }
917 }
918
919
920
921
922
923 private final class ColumnMatchIterator extends BaseIterator
924 {
925 private final ColumnImpl _columnPattern;
926 private final Object _valuePattern;
927 private final Object _searchInfo;
928
929 private ColumnMatchIterator(Collection<String> columnNames,
930 ColumnImpl columnPattern, Object valuePattern,
931 boolean reset, boolean moveForward,
932 ColumnMatcher columnMatcher)
933 {
934 super(columnNames, reset, moveForward, columnMatcher);
935 _columnPattern = columnPattern;
936 _valuePattern = valuePattern;
937 _searchInfo = prepareSearchInfo(columnPattern, valuePattern);
938 }
939
940 @Override
941 protected boolean findNext() throws IOException {
942 return findAnotherRow(_columnPattern, _valuePattern, false, _moveForward,
943 _colMatcher, _searchInfo);
944 }
945 }
946
947
948
949
950
951 private final class RowMatchIterator extends BaseIterator
952 {
953 private final Map<String,?> _rowPattern;
954 private final Object _searchInfo;
955
956 private RowMatchIterator(Collection<String> columnNames,
957 Map<String,?> rowPattern,
958 boolean reset, boolean moveForward,
959 ColumnMatcher columnMatcher)
960 {
961 super(columnNames, reset, moveForward, columnMatcher);
962 _rowPattern = rowPattern;
963 _searchInfo = prepareSearchInfo(rowPattern);
964 }
965
966 @Override
967 protected boolean findNext() throws IOException {
968 return findAnotherRow(_rowPattern, false, _moveForward, _colMatcher,
969 _searchInfo);
970 }
971 }
972
973
974
975
976
977
978 protected abstract class DirHandler
979 {
980 public abstract PositionImpl getBeginningPosition();
981 public abstract PositionImpl getEndPosition();
982 }
983
984
985
986
987
988
989
990 protected static final class IdImpl implements Id
991 {
992 private final int _tablePageNumber;
993 private final int _indexNumber;
994
995 protected IdImpl(TableImpl table, IndexImpl index) {
996 _tablePageNumber = table.getTableDefPageNumber();
997 _indexNumber = ((index != null) ? index.getIndexNumber() : -1);
998 }
999
1000 @Override
1001 public int hashCode() {
1002 return _tablePageNumber;
1003 }
1004
1005 @Override
1006 public boolean equals(Object o) {
1007 return((this == o) ||
1008 ((o != null) && (getClass() == o.getClass()) &&
1009 (_tablePageNumber == ((IdImpl)o)._tablePageNumber) &&
1010 (_indexNumber == ((IdImpl)o)._indexNumber)));
1011 }
1012
1013 @Override
1014 public String toString() {
1015 return getClass().getSimpleName() + " " + _tablePageNumber + ":" + _indexNumber;
1016 }
1017 }
1018
1019
1020
1021
1022 protected static abstract class PositionImpl implements Position
1023 {
1024 protected PositionImpl() {
1025 }
1026
1027 @Override
1028 public final int hashCode() {
1029 return getRowId().hashCode();
1030 }
1031
1032 @Override
1033 public final boolean equals(Object o) {
1034 return((this == o) ||
1035 ((o != null) && (getClass() == o.getClass()) && equalsImpl(o)));
1036 }
1037
1038
1039
1040
1041 @Override
1042 public abstract RowIdImpl getRowId();
1043
1044
1045
1046
1047
1048
1049
1050 protected abstract boolean equalsImpl(Object o);
1051 }
1052
1053
1054
1055
1056 protected static final class SavepointImpl implements Savepoint
1057 {
1058 private final IdImpl _cursorId;
1059 private final PositionImpl _curPos;
1060 private final PositionImpl _prevPos;
1061
1062 private SavepointImpl(IdImpl cursorId, PositionImpl curPos,
1063 PositionImpl prevPos) {
1064 _cursorId = cursorId;
1065 _curPos = curPos;
1066 _prevPos = prevPos;
1067 }
1068
1069 @Override
1070 public IdImpl getCursorId() {
1071 return _cursorId;
1072 }
1073
1074 @Override
1075 public PositionImpl getCurrentPosition() {
1076 return _curPos;
1077 }
1078
1079 private PositionImpl getPreviousPosition() {
1080 return _prevPos;
1081 }
1082
1083 @Override
1084 public String toString() {
1085 return getClass().getSimpleName() + " " + _cursorId + " CurPosition " +
1086 _curPos + ", PrevPosition " + _prevPos;
1087 }
1088 }
1089
1090 }