1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package com.healthmarketscience.jackcess;
29
30 import java.io.File;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.TreeSet;
37
38 import junit.framework.TestCase;
39
40 import static com.healthmarketscience.jackcess.DatabaseTest.*;
41
42
43
44
45 public class CursorTest extends TestCase {
46
47 public CursorTest(String name) throws Exception {
48 super(name);
49 }
50
51 private static List<Map<String,Object>> createTestTableData()
52 throws Exception
53 {
54 List<Map<String,Object>> expectedRows =
55 new ArrayList<Map<String,Object>>();
56 for(int i = 0; i < 10; ++i) {
57 expectedRows.add(createExpectedRow("id", i, "value", "data" + i));
58 }
59 return expectedRows;
60 }
61
62 private static List<Map<String,Object>> createTestTableData(
63 int startIdx,
64 int endIdx)
65 throws Exception
66 {
67 List<Map<String,Object>> expectedRows = createTestTableData();
68 expectedRows.subList(endIdx, expectedRows.size()).clear();
69 expectedRows.subList(0, startIdx).clear();
70 return expectedRows;
71 }
72
73 private static Database createTestTable() throws Exception {
74 Database db = create();
75
76 Table table = new TableBuilder("test")
77 .addColumn(new ColumnBuilder("id", DataType.LONG).toColumn())
78 .addColumn(new ColumnBuilder("value", DataType.TEXT).toColumn())
79 .toTable(db);
80
81 for(Map<String,Object> row : createTestTableData()) {
82 table.addRow(row.get("id"), row.get("value"));
83 }
84
85 return db;
86 }
87
88 private static List<Map<String,Object>> createUnorderedTestTableData()
89 throws Exception
90 {
91 List<Map<String,Object>> expectedRows =
92 new ArrayList<Map<String,Object>>();
93 int[] ids = new int[]{3, 7, 6, 1, 2, 9, 0, 5, 4, 8};
94 for(int i : ids) {
95 expectedRows.add(createExpectedRow("id", i, "value", "data" + i));
96 }
97 return expectedRows;
98 }
99
100 static Database createTestIndexTable() throws Exception {
101 Database db = openCopy(new File("test/data/indexCursorTest.mdb"));
102
103 Table table = db.getTable("test");
104
105 for(Map<String,Object> row : createUnorderedTestTableData()) {
106 table.addRow(row.get("id"), row.get("value"));
107 }
108
109 return db;
110 }
111
112 private static Cursor createIndexSubRangeCursor(Table table,
113 Index idx,
114 int type)
115 throws Exception
116 {
117 return new CursorBuilder(table)
118 .setIndex(idx)
119 .setStartEntry(3 - type)
120 .setStartRowInclusive(type == 0)
121 .setEndEntry(8 + type)
122 .setEndRowInclusive(type == 0)
123 .toCursor();
124 }
125
126 public void testRowId() throws Exception {
127
128 RowId rowId1 = new RowId(1, 2);
129 RowId rowId2 = new RowId(1, 3);
130 RowId rowId3 = new RowId(2, 1);
131
132 List<RowId> sortedRowIds = new ArrayList<RowId>(new TreeSet<RowId>(
133 Arrays.asList(rowId1, rowId2, rowId3, RowId.FIRST_ROW_ID,
134 RowId.LAST_ROW_ID)));
135
136 assertEquals(Arrays.asList(RowId.FIRST_ROW_ID, rowId1, rowId2, rowId3,
137 RowId.LAST_ROW_ID),
138 sortedRowIds);
139 }
140
141 public void testSimple() throws Exception {
142 Database db = createTestTable();
143
144 Table table = db.getTable("test");
145 Cursor cursor = Cursor.createCursor(table);
146 doTestSimple(table, cursor, null);
147 db.close();
148 }
149
150 private void doTestSimple(Table table, Cursor cursor,
151 List<Map<String,Object>> expectedRows)
152 throws Exception
153 {
154 if(expectedRows == null) {
155 expectedRows = createTestTableData();
156 }
157
158 List<Map<String, Object>> foundRows =
159 new ArrayList<Map<String, Object>>();
160 for(Map<String, Object> row : cursor) {
161 foundRows.add(row);
162 }
163 assertEquals(expectedRows, foundRows);
164 }
165
166 public void testMove() throws Exception {
167 Database db = createTestTable();
168
169 Table table = db.getTable("test");
170 Cursor cursor = Cursor.createCursor(table);
171 doTestMove(table, cursor, null);
172
173 db.close();
174 }
175
176 private void doTestMove(Table table, Cursor cursor,
177 List<Map<String,Object>> expectedRows)
178 throws Exception
179 {
180 if(expectedRows == null) {
181 expectedRows = createTestTableData();
182 }
183 expectedRows.subList(1, 4).clear();
184
185 List<Map<String, Object>> foundRows =
186 new ArrayList<Map<String, Object>>();
187 assertTrue(cursor.isBeforeFirst());
188 assertFalse(cursor.isAfterLast());
189 foundRows.add(cursor.getNextRow());
190 assertEquals(3, cursor.moveNextRows(3));
191 assertFalse(cursor.isBeforeFirst());
192 assertFalse(cursor.isAfterLast());
193
194 Map<String,Object> expectedRow = cursor.getCurrentRow();
195 Cursor.Savepoint savepoint = cursor.getSavepoint();
196 assertEquals(2, cursor.movePreviousRows(2));
197 assertEquals(2, cursor.moveNextRows(2));
198 assertTrue(cursor.moveToNextRow());
199 assertTrue(cursor.moveToPreviousRow());
200 assertEquals(expectedRow, cursor.getCurrentRow());
201
202 while(cursor.moveToNextRow()) {
203 foundRows.add(cursor.getCurrentRow());
204 }
205 assertEquals(expectedRows, foundRows);
206 assertFalse(cursor.isBeforeFirst());
207 assertTrue(cursor.isAfterLast());
208
209 assertEquals(0, cursor.moveNextRows(3));
210
211 cursor.beforeFirst();
212 assertTrue(cursor.isBeforeFirst());
213 assertFalse(cursor.isAfterLast());
214
215 cursor.afterLast();
216 assertFalse(cursor.isBeforeFirst());
217 assertTrue(cursor.isAfterLast());
218
219 cursor.restoreSavepoint(savepoint);
220 assertEquals(expectedRow, cursor.getCurrentRow());
221 }
222
223 public void testSearch() throws Exception {
224 Database db = createTestTable();
225
226 Table table = db.getTable("test");
227 Cursor cursor = Cursor.createCursor(table);
228 doTestSearch(table, cursor, null, 42, -13);
229
230 db.close();
231 }
232
233 private void doTestSearch(Table table, Cursor cursor, Index index,
234 Integer... outOfRangeValues)
235 throws Exception
236 {
237 assertTrue(cursor.findRow(table.getColumn("id"), 3));
238 assertEquals(createExpectedRow("id", 3,
239 "value", "data" + 3),
240 cursor.getCurrentRow());
241
242 assertTrue(cursor.findRow(createExpectedRow(
243 "id", 6,
244 "value", "data" + 6)));
245 assertEquals(createExpectedRow("id", 6,
246 "value", "data" + 6),
247 cursor.getCurrentRow());
248
249 assertFalse(cursor.findRow(createExpectedRow(
250 "id", 8,
251 "value", "data" + 13)));
252 assertFalse(cursor.findRow(table.getColumn("id"), 13));
253 assertEquals(createExpectedRow("id", 6,
254 "value", "data" + 6),
255 cursor.getCurrentRow());
256
257 assertTrue(cursor.findRow(createExpectedRow(
258 "value", "data" + 7)));
259 assertEquals(createExpectedRow("id", 7,
260 "value", "data" + 7),
261 cursor.getCurrentRow());
262
263 assertTrue(cursor.findRow(table.getColumn("value"), "data" + 4));
264 assertEquals(createExpectedRow("id", 4,
265 "value", "data" + 4),
266 cursor.getCurrentRow());
267
268 for(Integer outOfRangeValue : outOfRangeValues) {
269 assertFalse(cursor.findRow(table.getColumn("id"),
270 outOfRangeValue));
271 assertFalse(cursor.findRow(table.getColumn("value"),
272 "data" + outOfRangeValue));
273 assertFalse(cursor.findRow(createExpectedRow(
274 "id", outOfRangeValue,
275 "value", "data" + outOfRangeValue)));
276 }
277
278 assertEquals("data" + 5,
279 Cursor.findValue(table,
280 table.getColumn("value"),
281 table.getColumn("id"), 5));
282 assertEquals(createExpectedRow("id", 5,
283 "value", "data" + 5),
284 Cursor.findRow(table,
285 createExpectedRow("id", 5)));
286 if(index != null) {
287 assertEquals("data" + 5,
288 Cursor.findValue(table, index,
289 table.getColumn("value"),
290 table.getColumn("id"), 5));
291 assertEquals(createExpectedRow("id", 5,
292 "value", "data" + 5),
293 Cursor.findRow(table, index,
294 createExpectedRow("id", 5)));
295
296 assertNull(Cursor.findValue(table, index,
297 table.getColumn("value"),
298 table.getColumn("id"),
299 -17));
300 assertNull(Cursor.findRow(table, index,
301 createExpectedRow("id", 13)));
302 }
303 }
304
305 public void testReverse() throws Exception {
306 Database db = createTestTable();
307
308 Table table = db.getTable("test");
309 Cursor cursor = Cursor.createCursor(table);
310 doTestReverse(table, cursor, null);
311
312 db.close();
313 }
314
315 private void doTestReverse(Table table, Cursor cursor,
316 List<Map<String,Object>> expectedRows)
317 throws Exception
318 {
319 if(expectedRows == null) {
320 expectedRows = createTestTableData();
321 }
322 Collections.reverse(expectedRows);
323
324 List<Map<String, Object>> foundRows =
325 new ArrayList<Map<String, Object>>();
326 for(Map<String, Object> row : cursor.reverseIterable()) {
327 foundRows.add(row);
328 }
329 assertEquals(expectedRows, foundRows);
330 }
331
332 public void testLiveAddition() throws Exception {
333 Database db = createTestTable();
334
335 Table table = db.getTable("test");
336
337 Cursor cursor1 = Cursor.createCursor(table);
338 Cursor cursor2 = Cursor.createCursor(table);
339 doTestLiveAddition(table, cursor1, cursor2, 11);
340
341 db.close();
342 }
343
344 private void doTestLiveAddition(Table table,
345 Cursor cursor1,
346 Cursor cursor2,
347 Integer newRowNum) throws Exception
348 {
349 cursor1.moveNextRows(11);
350 cursor2.moveNextRows(11);
351
352 assertTrue(cursor1.isAfterLast());
353 assertTrue(cursor2.isAfterLast());
354
355 table.addRow(newRowNum, "data" + newRowNum);
356 Map<String,Object> expectedRow =
357 createExpectedRow("id", newRowNum, "value", "data" + newRowNum);
358
359 assertFalse(cursor1.isAfterLast());
360 assertFalse(cursor2.isAfterLast());
361
362 assertEquals(expectedRow, cursor1.getCurrentRow());
363 assertEquals(expectedRow, cursor2.getCurrentRow());
364 assertFalse(cursor1.moveToNextRow());
365 assertFalse(cursor2.moveToNextRow());
366 assertTrue(cursor1.isAfterLast());
367 assertTrue(cursor2.isAfterLast());
368 }
369
370
371 public void testLiveDeletion() throws Exception {
372 Database db = createTestTable();
373
374 Table table = db.getTable("test");
375
376 Cursor cursor1 = Cursor.createCursor(table);
377 Cursor cursor2 = Cursor.createCursor(table);
378 Cursor cursor3 = Cursor.createCursor(table);
379 Cursor cursor4 = Cursor.createCursor(table);
380 doTestLiveDeletion(table, cursor1, cursor2, cursor3, cursor4, 1);
381
382 db.close();
383 }
384
385 private void doTestLiveDeletion(Table table,
386 Cursor cursor1,
387 Cursor cursor2,
388 Cursor cursor3,
389 Cursor cursor4,
390 int firstValue) throws Exception
391 {
392 assertEquals(2, cursor1.moveNextRows(2));
393 assertEquals(3, cursor2.moveNextRows(3));
394 assertEquals(3, cursor3.moveNextRows(3));
395 assertEquals(4, cursor4.moveNextRows(4));
396
397 Map<String,Object> expectedPrevRow =
398 createExpectedRow("id", firstValue, "value", "data" + firstValue);
399 ++firstValue;
400 Map<String,Object> expectedDeletedRow =
401 createExpectedRow("id", firstValue, "value", "data" + firstValue);
402 ++firstValue;
403 Map<String,Object> expectedNextRow =
404 createExpectedRow("id", firstValue, "value", "data" + firstValue);
405
406 assertEquals(expectedDeletedRow, cursor2.getCurrentRow());
407 assertEquals(expectedDeletedRow, cursor3.getCurrentRow());
408
409 assertFalse(cursor2.isCurrentRowDeleted());
410 assertFalse(cursor3.isCurrentRowDeleted());
411
412 cursor2.deleteCurrentRow();
413
414 assertTrue(cursor2.isCurrentRowDeleted());
415 assertTrue(cursor3.isCurrentRowDeleted());
416
417 assertEquals(expectedNextRow, cursor1.getNextRow());
418 assertEquals(expectedNextRow, cursor2.getNextRow());
419 assertEquals(expectedNextRow, cursor3.getNextRow());
420
421 assertEquals(expectedPrevRow, cursor3.getPreviousRow());
422
423 assertTrue(cursor3.moveToNextRow());
424 cursor3.deleteCurrentRow();
425 assertTrue(cursor3.isCurrentRowDeleted());
426
427 firstValue += 2;
428 expectedNextRow =
429 createExpectedRow("id", firstValue, "value", "data" + firstValue);
430 assertTrue(cursor3.moveToNextRow());
431 assertEquals(expectedNextRow, cursor3.getNextRow());
432
433 cursor1.beforeFirst();
434 assertTrue(cursor1.moveToNextRow());
435 cursor1.deleteCurrentRow();
436 assertFalse(cursor1.isBeforeFirst());
437 assertFalse(cursor1.isAfterLast());
438 assertFalse(cursor1.moveToPreviousRow());
439 assertTrue(cursor1.isBeforeFirst());
440 assertFalse(cursor1.isAfterLast());
441
442 cursor1.afterLast();
443 assertTrue(cursor1.moveToPreviousRow());
444 cursor1.deleteCurrentRow();
445 assertFalse(cursor1.isBeforeFirst());
446 assertFalse(cursor1.isAfterLast());
447 assertFalse(cursor1.moveToNextRow());
448 assertFalse(cursor1.isBeforeFirst());
449 assertTrue(cursor1.isAfterLast());
450
451 cursor1.beforeFirst();
452 while(cursor1.moveToNextRow()) {
453 cursor1.deleteCurrentRow();
454 }
455
456 assertTrue(cursor1.isAfterLast());
457 assertTrue(cursor2.isCurrentRowDeleted());
458 assertTrue(cursor3.isCurrentRowDeleted());
459 assertTrue(cursor4.isCurrentRowDeleted());
460 }
461
462 public void testSimpleIndex() throws Exception {
463 Database db = createTestIndexTable();
464
465 Table table = db.getTable("test");
466 Index idx = table.getIndexes().get(0);
467
468 assertTable(createUnorderedTestTableData(), table);
469
470 Cursor cursor = Cursor.createIndexCursor(table, idx);
471 doTestSimple(table, cursor, null);
472
473 db.close();
474 }
475
476 public void testMoveIndex() throws Exception {
477 Database db = createTestIndexTable();
478
479 Table table = db.getTable("test");
480 Index idx = table.getIndexes().get(0);
481 Cursor cursor = Cursor.createIndexCursor(table, idx);
482 doTestMove(table, cursor, null);
483
484 db.close();
485 }
486
487 public void testReverseIndex() throws Exception {
488 Database db = createTestIndexTable();
489
490 Table table = db.getTable("test");
491 Index idx = table.getIndexes().get(0);
492 Cursor cursor = Cursor.createIndexCursor(table, idx);
493 doTestReverse(table, cursor, null);
494
495 db.close();
496 }
497
498 public void testSearchIndex() throws Exception {
499 Database db = createTestIndexTable();
500
501 Table table = db.getTable("test");
502 Index idx = table.getIndexes().get(0);
503 Cursor cursor = Cursor.createIndexCursor(table, idx);
504 doTestSearch(table, cursor, idx, 42, -13);
505
506 db.close();
507 }
508
509 public void testLiveAdditionIndex() throws Exception {
510 Database db = createTestIndexTable();
511
512 Table table = db.getTable("test");
513 Index idx = table.getIndexes().get(0);
514
515 Cursor cursor1 = Cursor.createIndexCursor(table, idx);
516 Cursor cursor2 = Cursor.createIndexCursor(table, idx);
517 doTestLiveAddition(table, cursor1, cursor2, 11);
518
519 db.close();
520 }
521
522 public void testLiveDeletionIndex() throws Exception {
523 Database db = createTestIndexTable();
524
525 Table table = db.getTable("test");
526 Index idx = table.getIndexes().get(0);
527
528 Cursor cursor1 = Cursor.createIndexCursor(table, idx);
529 Cursor cursor2 = Cursor.createIndexCursor(table, idx);
530 Cursor cursor3 = Cursor.createIndexCursor(table, idx);
531 Cursor cursor4 = Cursor.createIndexCursor(table, idx);
532 doTestLiveDeletion(table, cursor1, cursor2, cursor3, cursor4, 1);
533
534 db.close();
535 }
536
537 public void testSimpleIndexSubRange() throws Exception {
538 for(int i = 0; i < 2; ++i) {
539 Database db = createTestIndexTable();
540
541 Table table = db.getTable("test");
542 Index idx = table.getIndexes().get(0);
543
544 Cursor cursor = createIndexSubRangeCursor(table, idx, i);
545
546 List<Map<String,Object>> expectedRows =
547 createTestTableData(3, 9);
548
549 doTestSimple(table, cursor, expectedRows);
550
551 db.close();
552 }
553 }
554
555 public void testMoveIndexSubRange() throws Exception {
556 for(int i = 0; i < 2; ++i) {
557 Database db = createTestIndexTable();
558
559 Table table = db.getTable("test");
560 Index idx = table.getIndexes().get(0);
561
562 Cursor cursor = createIndexSubRangeCursor(table, idx, i);
563
564 List<Map<String,Object>> expectedRows =
565 createTestTableData(3, 9);
566
567 doTestMove(table, cursor, expectedRows);
568
569 db.close();
570 }
571 }
572
573 public void testSearchIndexSubRange() throws Exception {
574 for(int i = 0; i < 2; ++i) {
575 Database db = createTestIndexTable();
576
577 Table table = db.getTable("test");
578 Index idx = table.getIndexes().get(0);
579
580 Cursor cursor = createIndexSubRangeCursor(table, idx, i);
581
582 doTestSearch(table, cursor, idx, 2, 9);
583
584 db.close();
585 }
586 }
587
588 public void testReverseIndexSubRange() throws Exception {
589 for(int i = 0; i < 2; ++i) {
590 Database db = createTestIndexTable();
591
592 Table table = db.getTable("test");
593 Index idx = table.getIndexes().get(0);
594
595 Cursor cursor = createIndexSubRangeCursor(table, idx, i);
596
597 List<Map<String,Object>> expectedRows =
598 createTestTableData(3, 9);
599
600 doTestReverse(table, cursor, expectedRows);
601
602 db.close();
603 }
604 }
605
606 public void testLiveAdditionIndexSubRange() throws Exception {
607 for(int i = 0; i < 2; ++i) {
608 Database db = createTestIndexTable();
609
610 Table table = db.getTable("test");
611 Index idx = table.getIndexes().get(0);
612
613 Cursor cursor1 = createIndexSubRangeCursor(table, idx, i);
614 Cursor cursor2 = createIndexSubRangeCursor(table, idx, i);
615
616 doTestLiveAddition(table, cursor1, cursor2, 8);
617
618 db.close();
619 }
620 }
621
622 public void testLiveDeletionIndexSubRange() throws Exception {
623 for(int i = 0; i < 2; ++i) {
624 Database db = createTestIndexTable();
625
626 Table table = db.getTable("test");
627 Index idx = table.getIndexes().get(0);
628
629 Cursor cursor1 = createIndexSubRangeCursor(table, idx, i);
630 Cursor cursor2 = createIndexSubRangeCursor(table, idx, i);
631 Cursor cursor3 = createIndexSubRangeCursor(table, idx, i);
632 Cursor cursor4 = createIndexSubRangeCursor(table, idx, i);
633
634 doTestLiveDeletion(table, cursor1, cursor2, cursor3, cursor4, 4);
635
636 db.close();
637 }
638 }
639
640 public void testId() throws Exception
641 {
642 Database db = createTestIndexTable();
643
644 Table table = db.getTable("test");
645 Index idx = table.getIndexes().get(0);
646
647 Cursor tCursor = Cursor.createCursor(table);
648 Cursor iCursor = Cursor.createIndexCursor(table, idx);
649
650 Cursor.Savepoint tSave = tCursor.getSavepoint();
651 Cursor.Savepoint iSave = iCursor.getSavepoint();
652
653 tCursor.restoreSavepoint(tSave);
654 iCursor.restoreSavepoint(iSave);
655
656 try {
657 tCursor.restoreSavepoint(iSave);
658 fail("IllegalArgumentException should have been thrown");
659 } catch(IllegalArgumentException e) {
660
661 }
662
663 try {
664 iCursor.restoreSavepoint(tSave);
665 fail("IllegalArgumentException should have been thrown");
666 } catch(IllegalArgumentException e) {
667
668 }
669
670 Cursor tCursor2 = Cursor.createCursor(table);
671 Cursor iCursor2 = Cursor.createIndexCursor(table, idx);
672
673 tCursor2.restoreSavepoint(tSave);
674 iCursor2.restoreSavepoint(iSave);
675
676 db.close();
677 }
678
679 }