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