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