1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.healthmarketscience.jackcess;
18
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.SortedSet;
26 import java.util.TreeSet;
27
28 import static com.healthmarketscience.jackcess.Database.*;
29 import com.healthmarketscience.jackcess.impl.ByteUtil;
30 import com.healthmarketscience.jackcess.impl.IndexCodesTest;
31 import com.healthmarketscience.jackcess.impl.IndexData;
32 import com.healthmarketscience.jackcess.impl.IndexImpl;
33 import static com.healthmarketscience.jackcess.impl.JetFormatTest.*;
34 import com.healthmarketscience.jackcess.impl.RowIdImpl;
35 import com.healthmarketscience.jackcess.impl.TableImpl;
36 import junit.framework.TestCase;
37 import static com.healthmarketscience.jackcess.TestUtil.*;
38 import static com.healthmarketscience.jackcess.DatabaseBuilder.*;
39
40
41
42
43 public class IndexTest extends TestCase {
44
45 public IndexTest(String name) {
46 super(name);
47 }
48
49 @Override
50 protected void setUp() {
51 TestUtil.setTestAutoSync(false);
52 }
53
54 @Override
55 protected void tearDown() {
56 TestUtil.clearTestAutoSync();
57 }
58
59 public void testByteOrder() throws Exception {
60 byte b1 = (byte)0x00;
61 byte b2 = (byte)0x01;
62 byte b3 = (byte)0x7F;
63 byte b4 = (byte)0x80;
64 byte b5 = (byte)0xFF;
65
66 assertTrue(ByteUtil.asUnsignedByte(b1) < ByteUtil.asUnsignedByte(b2));
67 assertTrue(ByteUtil.asUnsignedByte(b2) < ByteUtil.asUnsignedByte(b3));
68 assertTrue(ByteUtil.asUnsignedByte(b3) < ByteUtil.asUnsignedByte(b4));
69 assertTrue(ByteUtil.asUnsignedByte(b4) < ByteUtil.asUnsignedByte(b5));
70 }
71
72 public void testByteCodeComparator() {
73 byte[] b0 = null;
74 byte[] b1 = new byte[]{(byte)0x00};
75 byte[] b2 = new byte[]{(byte)0x00, (byte)0x00};
76 byte[] b3 = new byte[]{(byte)0x00, (byte)0x01};
77 byte[] b4 = new byte[]{(byte)0x01};
78 byte[] b5 = new byte[]{(byte)0x80};
79 byte[] b6 = new byte[]{(byte)0xFF};
80 byte[] b7 = new byte[]{(byte)0xFF, (byte)0x00};
81 byte[] b8 = new byte[]{(byte)0xFF, (byte)0x01};
82
83 List<byte[]> expectedList = Arrays.<byte[]>asList(b0, b1, b2, b3, b4,
84 b5, b6, b7, b8);
85 SortedSet<byte[]> sortedSet = new TreeSet<byte[]>(
86 IndexData.BYTE_CODE_COMPARATOR);
87 sortedSet.addAll(expectedList);
88 assertEquals(expectedList, new ArrayList<byte[]>(sortedSet));
89
90 }
91
92 public void testPrimaryKey() throws Exception {
93 for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
94 Table table = open(testDB).getTable("Table1");
95 Map<String, Boolean> foundPKs = new HashMap<String, Boolean>();
96 Index pkIndex = null;
97 for(Index index : table.getIndexes()) {
98 foundPKs.put(index.getColumns().iterator().next().getName(),
99 index.isPrimaryKey());
100 if(index.isPrimaryKey()) {
101 pkIndex= index;
102
103 }
104 }
105 Map<String, Boolean> expectedPKs = new HashMap<String, Boolean>();
106 expectedPKs.put("A", Boolean.TRUE);
107 expectedPKs.put("B", Boolean.FALSE);
108 assertEquals(expectedPKs, foundPKs);
109 assertSame(pkIndex, table.getPrimaryKeyIndex());
110 }
111 }
112
113 public void testLogicalIndexes() throws Exception
114 {
115 for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX, true)) {
116 Database mdb = open(testDB);
117
118 TableImpl table = (TableImpl)mdb.getTable("Table1");
119 for(IndexImpl idx : table.getIndexes()) {
120 idx.initialize();
121 }
122 assertEquals(4, table.getIndexes().size());
123 assertEquals(4, table.getLogicalIndexCount());
124 checkIndexColumns(table,
125 "id", "id",
126 "PrimaryKey", "id",
127 "Table2Table1", "otherfk1",
128 "Table3Table1", "otherfk2");
129
130 table = (TableImpl)mdb.getTable("Table2");
131 for(IndexImpl idx : table.getIndexes()) {
132 idx.initialize();
133 }
134 assertEquals(3, table.getIndexes().size());
135 assertEquals(2, table.getIndexDatas().size());
136 assertEquals(3, table.getLogicalIndexCount());
137 checkIndexColumns(table,
138 "id", "id",
139 "PrimaryKey", "id",
140 ".rC", "id");
141
142 IndexImpl pkIdx = table.getIndex("PrimaryKey");
143 IndexImpl fkIdx = table.getIndex(".rC");
144 assertNotSame(pkIdx, fkIdx);
145 assertTrue(fkIdx.isForeignKey());
146 assertSame(pkIdx.getIndexData(), fkIdx.getIndexData());
147 IndexData indexData = pkIdx.getIndexData();
148 assertEquals(Arrays.asList(pkIdx, fkIdx), indexData.getIndexes());
149 assertSame(pkIdx, indexData.getPrimaryIndex());
150
151 table = (TableImpl)mdb.getTable("Table3");
152 for(IndexImpl idx : table.getIndexes()) {
153 idx.initialize();
154 }
155 assertEquals(3, table.getIndexes().size());
156 assertEquals(2, table.getIndexDatas().size());
157 assertEquals(3, table.getLogicalIndexCount());
158 checkIndexColumns(table,
159 "id", "id",
160 "PrimaryKey", "id",
161 ".rC", "id");
162
163 pkIdx = table.getIndex("PrimaryKey");
164 fkIdx = table.getIndex(".rC");
165 assertNotSame(pkIdx, fkIdx);
166 assertTrue(fkIdx.isForeignKey());
167 assertSame(pkIdx.getIndexData(), fkIdx.getIndexData());
168 indexData = pkIdx.getIndexData();
169 assertEquals(Arrays.asList(pkIdx, fkIdx), indexData.getIndexes());
170 assertSame(pkIdx, indexData.getPrimaryIndex());
171 }
172 }
173
174 public void testComplexIndex() throws Exception
175 {
176 for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.COMP_INDEX)) {
177
178 Database db = open(testDB);
179 TableImpl t = (TableImpl)db.getTable("Table1");
180 IndexImpl index = t.getIndexes().get(0);
181 assertFalse(index.isInitialized());
182 assertEquals(512, countRows(t));
183 assertEquals(512, index.getIndexData().getEntryCount());
184 db.close();
185
186
187 db = openCopy(testDB);
188 t = (TableImpl)db.getTable("Table1");
189 index = t.getIndexes().get(0);
190
191 t.addRow(99, "abc", "def");
192 }
193 }
194
195 public void testEntryDeletion() throws Exception {
196 for (final TestDB testDB : SUPPORTED_DBS_TEST) {
197 Table table = openCopy(testDB).getTable("Table1");
198
199 for(int i = 0; i < 10; ++i) {
200 table.addRow("foo" + i, "bar" + i, (byte)42 + i, (short)53 + i, 13 * i,
201 (6.7d / i), null, null, true);
202 }
203 table.reset();
204 assertRowCount(12, table);
205
206 for(Index index : table.getIndexes()) {
207 assertEquals(12, ((IndexImpl)index).getIndexData().getEntryCount());
208 }
209
210 table.reset();
211 table.getNextRow();
212 table.getNextRow();
213 table.getDefaultCursor().deleteCurrentRow();
214 table.getNextRow();
215 table.getDefaultCursor().deleteCurrentRow();
216 table.getNextRow();
217 table.getNextRow();
218 table.getDefaultCursor().deleteCurrentRow();
219 table.getNextRow();
220 table.getNextRow();
221 table.getNextRow();
222 table.getDefaultCursor().deleteCurrentRow();
223
224 table.reset();
225 assertRowCount(8, table);
226
227 for(Index index : table.getIndexes()) {
228 assertEquals(8, ((IndexImpl)index).getIndexData().getEntryCount());
229 }
230 }
231 }
232
233 public void testIgnoreNulls() throws Exception
234 {
235 for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX_PROPERTIES)) {
236 Database db = openCopy(testDB);
237
238 db.setEvaluateExpressions(false);
239
240 doTestIgnoreNulls(db, "TableIgnoreNulls1");
241 doTestIgnoreNulls(db, "TableIgnoreNulls2");
242
243 db.close();
244 }
245 }
246
247 private void doTestIgnoreNulls(Database db, String tableName)
248 throws Exception
249 {
250 Table orig = db.getTable(tableName);
251 IndexImpl origI = (IndexImpl)orig.getIndex("DataIndex");
252 Table temp = db.getTable(tableName + "_temp");
253 IndexImpl tempI = (IndexImpl)temp.getIndex("DataIndex");
254
255
256 for(Map<String,Object> row : orig) {
257 temp.addRow(orig.asRow(row));
258 }
259
260 assertEquals(origI.getIndexData().getEntryCount(),
261 tempI.getIndexData().getEntryCount());
262
263 Cursor origC = origI.newCursor().toCursor();
264 Cursor tempC = tempI.newCursor().toCursor();
265
266 while(true) {
267 boolean origHasNext = origC.moveToNextRow();
268 boolean tempHasNext = tempC.moveToNextRow();
269 assertTrue(origHasNext == tempHasNext);
270 if(!origHasNext) {
271 break;
272 }
273
274 Map<String,Object> origRow = origC.getCurrentRow();
275 Cursor.Position origCurPos = origC.getSavepoint().getCurrentPosition();
276 Map<String,Object> tempRow = tempC.getCurrentRow();
277 Cursor.Position tempCurPos = tempC.getSavepoint().getCurrentPosition();
278
279 assertEquals(origRow, tempRow);
280 assertEquals(IndexCodesTest.entryToString(origCurPos),
281 IndexCodesTest.entryToString(tempCurPos));
282 }
283 }
284
285 public void testUnique() throws Exception
286 {
287 for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX_PROPERTIES)) {
288 Database db = openCopy(testDB);
289
290 Table t = db.getTable("TableUnique1_temp");
291 Index index = t.getIndex("DataIndex");
292
293 doTestUnique(index, 1,
294 null, true,
295 "unique data", true,
296 null, true,
297 "more", false,
298 "stuff", false,
299 "unique data", false);
300
301 t = db.getTable("TableUnique2_temp");
302 index = t.getIndex("DataIndex");
303
304 doTestUnique(index, 2,
305 null, null, true,
306 "unique data", 42, true,
307 "unique data", null, true,
308 null, null, true,
309 "some", 42, true,
310 "more unique data", 13, true,
311 null, -4242, true,
312 "another row", -3462, false,
313 null, 49, false,
314 "more", null, false,
315 "unique data", 42, false,
316 "unique data", null, false,
317 null, -4242, false);
318
319 db.close();
320 }
321 }
322
323 private void doTestUnique(Index index, int numValues,
324 Object... testData)
325 throws Exception
326 {
327 for(int i = 0; i < testData.length; i += (numValues + 1)) {
328 Object[] row = new Object[numValues + 1];
329 row[0] = "testRow" + i;
330 for(int j = 1; j < (numValues + 1); ++j) {
331 row[j] = testData[i + j - 1];
332 }
333 boolean expectedSuccess = (Boolean)testData[i + numValues];
334
335 IOException failure = null;
336 try {
337 ((IndexImpl)index).getIndexData().prepareAddRow(
338 row, new RowIdImpl(400 + i, 0), null).commit();
339 } catch(IOException e) {
340 failure = e;
341 }
342 if(expectedSuccess) {
343 assertNull(failure);
344 } else {
345 assertNotNull(failure);
346 assertTrue(failure.getMessage().contains("uniqueness"));
347 }
348 }
349 }
350
351 public void testUniqueEntryCount() throws Exception {
352 for (final TestDB testDB : SUPPORTED_DBS_TEST) {
353 Database db = openCopy(testDB);
354 db.setDateTimeType(DateTimeType.DATE);
355 Table table = db.getTable("Table1");
356 IndexImpl indA = (IndexImpl)table.getIndex("PrimaryKey");
357 IndexImpl indB = (IndexImpl)table.getIndex("B");
358
359 assertEquals(2, indA.getUniqueEntryCount());
360 assertEquals(2, indB.getUniqueEntryCount());
361
362 List<String> bElems = Arrays.asList("bar", null, "baz", "argle", null,
363 "bazzle", "37", "bar", "bar", "BAZ");
364
365 for(int i = 0; i < 10; ++i) {
366 table.addRow("foo" + i, bElems.get(i), (byte)42 + i, (short)53 + i,
367 13 * i, (6.7d / i), null, null, true);
368 }
369
370 assertEquals(12, indA.getIndexData().getEntryCount());
371 assertEquals(12, indB.getIndexData().getEntryCount());
372
373 assertEquals(12, indA.getUniqueEntryCount());
374 assertEquals(8, indB.getUniqueEntryCount());
375
376 table = null;
377 indA = null;
378 indB = null;
379
380 table = db.getTable("Table1");
381 indA = (IndexImpl)table.getIndex("PrimaryKey");
382 indB = (IndexImpl)table.getIndex("B");
383
384 assertEquals(12, indA.getIndexData().getEntryCount());
385 assertEquals(12, indB.getIndexData().getEntryCount());
386
387 assertEquals(12, indA.getUniqueEntryCount());
388 assertEquals(8, indB.getUniqueEntryCount());
389
390 Cursor c = CursorBuilder.createCursor(table);
391 assertTrue(c.moveToNextRow());
392
393 final Row row = c.getCurrentRow();
394
395 if (testDB.getExpectedFileFormat().ordinal() >=
396 Database.FileFormat.V2007.ordinal()) {
397 TestUtil.checkTestDBTable1RowA(testDB, table, row);
398 } else {
399 TestUtil.checkTestDBTable1RowABCDEFG(testDB, table, row);
400 }
401 c.deleteCurrentRow();
402
403 assertEquals(11, indA.getIndexData().getEntryCount());
404 assertEquals(11, indB.getIndexData().getEntryCount());
405
406 assertEquals(12, indA.getUniqueEntryCount());
407 assertEquals(8, indB.getUniqueEntryCount());
408
409 db.close();
410 }
411 }
412
413 public void testReplId() throws Exception
414 {
415 for (final TestDB testDB : SUPPORTED_DBS_TEST) {
416 Database db = openCopy(testDB);
417 Table table = db.getTable("Table4");
418
419 for(int i = 0; i< 20; ++i) {
420 table.addRow("row" + i, Column.AUTO_NUMBER);
421 }
422
423 assertEquals(20, table.getRowCount());
424
425 db.close();
426 }
427 }
428
429 public void testIndexCreation() throws Exception
430 {
431 for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
432 Database db = create(fileFormat);
433
434 Table t = newTable("TestTable")
435 .addColumn(newColumn("id", DataType.LONG))
436 .addColumn(newColumn("data", DataType.TEXT))
437 .setPrimaryKey("id")
438 .toTable(db);
439
440 assertEquals(1, t.getIndexes().size());
441 IndexImpl idx = (IndexImpl)t.getIndexes().get(0);
442
443 assertEquals(IndexBuilder.PRIMARY_KEY_NAME, idx.getName());
444 assertEquals(1, idx.getColumns().size());
445 assertEquals("id", idx.getColumns().get(0).getName());
446 assertTrue(idx.getColumns().get(0).isAscending());
447 assertTrue(idx.isPrimaryKey());
448 assertTrue(idx.isUnique());
449 assertFalse(idx.shouldIgnoreNulls());
450 assertNull(idx.getReference());
451
452 t.addRow(2, "row2");
453 t.addRow(1, "row1");
454 t.addRow(3, "row3");
455
456 Cursor c = t.newCursor()
457 .setIndexByName(IndexBuilder.PRIMARY_KEY_NAME).toCursor();
458
459 for(int i = 1; i <= 3; ++i) {
460 Map<String,Object> row = c.getNextRow();
461 assertEquals(i, row.get("id"));
462 assertEquals("row" + i, row.get("data"));
463 }
464 assertFalse(c.moveToNextRow());
465 }
466 }
467
468 public void testIndexCreationSharedData() throws Exception
469 {
470 for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
471 Database db = create(fileFormat);
472
473 Table t = newTable("TestTable")
474 .addColumn(newColumn("id", DataType.LONG))
475 .addColumn(newColumn("data", DataType.TEXT))
476 .setPrimaryKey("id")
477 .addIndex(newIndex("Index1").addColumns("id"))
478 .addIndex(newIndex("Index2").addColumns("id"))
479 .addIndex(newIndex("Index3").addColumns(false, "id"))
480 .toTable(db);
481
482 assertEquals(4, t.getIndexes().size());
483 IndexImpl idx = (IndexImpl)t.getIndexes().get(0);
484
485 assertEquals(IndexBuilder.PRIMARY_KEY_NAME, idx.getName());
486 assertEquals(1, idx.getColumns().size());
487 assertEquals("id", idx.getColumns().get(0).getName());
488 assertTrue(idx.getColumns().get(0).isAscending());
489 assertTrue(idx.isPrimaryKey());
490 assertTrue(idx.isUnique());
491 assertFalse(idx.shouldIgnoreNulls());
492 assertNull(idx.getReference());
493
494 IndexImpl idx1 = (IndexImpl)t.getIndexes().get(1);
495 IndexImpl idx2 = (IndexImpl)t.getIndexes().get(2);
496 IndexImpl idx3 = (IndexImpl)t.getIndexes().get(3);
497
498 assertNotSame(idx.getIndexData(), idx1.getIndexData());
499 assertSame(idx1.getIndexData(), idx2.getIndexData());
500 assertNotSame(idx2.getIndexData(), idx3.getIndexData());
501
502 t.addRow(2, "row2");
503 t.addRow(1, "row1");
504 t.addRow(3, "row3");
505
506 Cursor c = t.newCursor()
507 .setIndexByName(IndexBuilder.PRIMARY_KEY_NAME).toCursor();
508
509 for(int i = 1; i <= 3; ++i) {
510 Map<String,Object> row = c.getNextRow();
511 assertEquals(i, row.get("id"));
512 assertEquals("row" + i, row.get("data"));
513 }
514 assertFalse(c.moveToNextRow());
515 }
516 }
517
518 public void testGetForeignKeyIndex() throws Exception
519 {
520 for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX, true)) {
521 Database db = open(testDB);
522 Table t1 = db.getTable("Table1");
523 Table t2 = db.getTable("Table2");
524 Table t3 = db.getTable("Table3");
525
526 IndexImpl t2t1 = (IndexImpl)t1.getIndex("Table2Table1");
527 IndexImpl t3t1 = (IndexImpl)t1.getIndex("Table3Table1");
528
529
530 assertTrue(t2t1.isForeignKey());
531 assertNotNull(t2t1.getReference());
532 assertFalse(t2t1.getReference().isPrimaryTable());
533 assertFalse(t2t1.getReference().isCascadeUpdates());
534 assertTrue(t2t1.getReference().isCascadeDeletes());
535 doCheckForeignKeyIndex(t1, t2t1, t2);
536
537 assertTrue(t3t1.isForeignKey());
538 assertNotNull(t3t1.getReference());
539 assertFalse(t3t1.getReference().isPrimaryTable());
540 assertTrue(t3t1.getReference().isCascadeUpdates());
541 assertFalse(t3t1.getReference().isCascadeDeletes());
542 doCheckForeignKeyIndex(t1, t3t1, t3);
543
544 Index t1pk = t1.getIndex(IndexBuilder.PRIMARY_KEY_NAME);
545 assertNotNull(t1pk);
546 assertNull(((IndexImpl)t1pk).getReference());
547 assertNull(t1pk.getReferencedIndex());
548 }
549 }
550
551 public void testConstraintViolation() throws Exception
552 {
553 for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
554 Database db = create(fileFormat);
555
556 Table t = newTable("TestTable")
557 .addColumn(newColumn("id", DataType.LONG))
558 .addColumn(newColumn("data", DataType.TEXT))
559 .setPrimaryKey("id")
560 .addIndex(newIndex("data_ind")
561 .addColumns("data").setUnique())
562 .toTable(db);
563
564 for(int i = 0; i < 5; ++i) {
565 t.addRow(i, "row" + i);
566 }
567
568 try {
569 t.addRow(3, "badrow");
570 fail("ConstraintViolationException should have been thrown");
571 } catch(ConstraintViolationException ce) {
572
573 }
574
575 assertEquals(5, t.getRowCount());
576
577 List<Row> expectedRows =
578 createExpectedTable(
579 createExpectedRow(
580 "id", 0, "data", "row0"),
581 createExpectedRow(
582 "id", 1, "data", "row1"),
583 createExpectedRow(
584 "id", 2, "data", "row2"),
585 createExpectedRow(
586 "id", 3, "data", "row3"),
587 createExpectedRow(
588 "id", 4, "data", "row4"));
589
590 assertTable(expectedRows, t);
591
592 IndexCursor pkCursor = CursorBuilder.createPrimaryKeyCursor(t);
593 assertCursor(expectedRows, pkCursor);
594
595 assertCursor(expectedRows,
596 CursorBuilder.createCursor(t.getIndex("data_ind")));
597
598 List<Object[]> batch = new ArrayList<Object[]>();
599 batch.add(new Object[]{5, "row5"});
600 batch.add(new Object[]{6, "row6"});
601 batch.add(new Object[]{7, "row2"});
602 batch.add(new Object[]{8, "row8"});
603
604 try {
605 t.addRows(batch);
606 fail("BatchUpdateException should have been thrown");
607 } catch(BatchUpdateException be) {
608
609 assertTrue(be.getCause() instanceof ConstraintViolationException);
610 assertEquals(2, be.getUpdateCount());
611 }
612
613 expectedRows = new ArrayList<Row>(expectedRows);
614 expectedRows.add(createExpectedRow("id", 5, "data", "row5"));
615 expectedRows.add(createExpectedRow("id", 6, "data", "row6"));
616
617 assertTable(expectedRows, t);
618
619 assertCursor(expectedRows, pkCursor);
620
621 assertCursor(expectedRows,
622 CursorBuilder.createCursor(t.getIndex("data_ind")));
623
624 pkCursor.findFirstRowByEntry(4);
625 Row row4 = pkCursor.getCurrentRow();
626
627 row4.put("id", 3);
628
629 try {
630 t.updateRow(row4);
631 fail("ConstraintViolationException should have been thrown");
632 } catch(ConstraintViolationException ce) {
633
634 }
635
636 assertTable(expectedRows, t);
637
638 assertCursor(expectedRows, pkCursor);
639
640 assertCursor(expectedRows,
641 CursorBuilder.createCursor(t.getIndex("data_ind")));
642
643 db.close();
644 }
645 }
646
647 public void testAutoNumberRecover() throws Exception
648 {
649 for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
650 Database db = create(fileFormat);
651
652 Table t = newTable("TestTable")
653 .addColumn(newColumn("id", DataType.LONG).setAutoNumber(true))
654 .addColumn(newColumn("data", DataType.TEXT))
655 .setPrimaryKey("id")
656 .addIndex(newIndex("data_ind")
657 .addColumns("data").setUnique())
658 .toTable(db);
659
660 for(int i = 1; i < 3; ++i) {
661 t.addRow(null, "row" + i);
662 }
663
664 try {
665 t.addRow(null, "row1");
666 fail("ConstraintViolationException should have been thrown");
667 } catch(ConstraintViolationException ce) {
668
669 }
670
671 t.addRow(null, "row3");
672
673 assertEquals(3, t.getRowCount());
674
675 List<Row> expectedRows =
676 createExpectedTable(
677 createExpectedRow(
678 "id", 1, "data", "row1"),
679 createExpectedRow(
680 "id", 2, "data", "row2"),
681 createExpectedRow(
682 "id", 3, "data", "row3"));
683
684 assertTable(expectedRows, t);
685
686 IndexCursor pkCursor = CursorBuilder.createPrimaryKeyCursor(t);
687 assertCursor(expectedRows, pkCursor);
688
689 assertCursor(expectedRows,
690 CursorBuilder.createCursor(t.getIndex("data_ind")));
691
692 List<Object[]> batch = new ArrayList<Object[]>();
693 batch.add(new Object[]{null, "row4"});
694 batch.add(new Object[]{null, "row5"});
695 batch.add(new Object[]{null, "row3"});
696
697 try {
698 t.addRows(batch);
699 fail("BatchUpdateException should have been thrown");
700 } catch(BatchUpdateException be) {
701
702 assertTrue(be.getCause() instanceof ConstraintViolationException);
703 assertEquals(2, be.getUpdateCount());
704 }
705
706 expectedRows = new ArrayList<Row>(expectedRows);
707 expectedRows.add(createExpectedRow("id", 4, "data", "row4"));
708 expectedRows.add(createExpectedRow("id", 5, "data", "row5"));
709
710 assertTable(expectedRows, t);
711
712 assertCursor(expectedRows, pkCursor);
713
714 assertCursor(expectedRows,
715 CursorBuilder.createCursor(t.getIndex("data_ind")));
716
717 db.close();
718 }
719 }
720
721 public void testBinaryIndex() throws Exception
722 {
723 for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.BINARY_INDEX)) {
724 Database db = open(testDB);
725
726 Table table = db.getTable("Test");
727
728 Index idx = table.getIndex("BinAscIdx");
729 doTestBinaryIndex(idx, "BinAsc", false);
730
731 idx = table.getIndex("BinDscIdx");
732 doTestBinaryIndex(idx, "BinDsc", true);
733
734 db.close();
735 }
736 }
737
738 private static void doTestBinaryIndex(Index idx, String colName, boolean forward)
739 throws Exception
740 {
741 IndexCursor ic = CursorBuilder.createCursor(idx);
742
743 for(Row row : idx.getTable().getDefaultCursor().newIterable().setForward(forward)) {
744 int id = row.getInt("ID");
745 byte[] data = row.getBytes(colName);
746
747 boolean found = false;
748 for(Row idxRow : ic.newEntryIterable(data)) {
749
750 assertTrue(Arrays.equals(data, idxRow.getBytes(colName)));
751 if(id == idxRow.getInt("ID")) {
752 found = true;
753 }
754 }
755
756 assertTrue(found);
757 }
758 }
759
760 private void doCheckForeignKeyIndex(Table ta, Index ia, Table tb)
761 throws Exception
762 {
763 IndexImpl ib = (IndexImpl)ia.getReferencedIndex();
764 assertNotNull(ib);
765 assertSame(tb, ib.getTable());
766
767 assertNotNull(ib.getReference());
768 assertSame(ia, ib.getReferencedIndex());
769 assertTrue(ib.getReference().isPrimaryTable());
770 }
771
772 private void checkIndexColumns(Table table, String... idxInfo)
773 throws Exception
774 {
775 Map<String, String> expectedIndexes = new HashMap<String, String>();
776 for(int i = 0; i < idxInfo.length; i+=2) {
777 expectedIndexes.put(idxInfo[i], idxInfo[i+1]);
778 }
779
780 for(Index idx : table.getIndexes()) {
781 String colName = expectedIndexes.get(idx.getName());
782 assertEquals(1, idx.getColumns().size());
783 assertEquals(colName, idx.getColumns().get(0).getName());
784 if("PrimaryKey".equals(idx.getName())) {
785 assertTrue(idx.isPrimaryKey());
786 } else {
787 assertFalse(idx.isPrimaryKey());
788 }
789 }
790 }
791
792 }