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.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.SortedSet;
38 import java.util.TreeSet;
39
40 import junit.framework.TestCase;
41
42 import static com.healthmarketscience.jackcess.DatabaseTest.*;
43
44
45
46
47 public class IndexTest extends TestCase {
48
49
50
51
52
53 public IndexTest(String name) {
54 super(name);
55 }
56
57 public void testByteOrder() throws Exception {
58 byte b1 = (byte)0x00;
59 byte b2 = (byte)0x01;
60 byte b3 = (byte)0x7F;
61 byte b4 = (byte)0x80;
62 byte b5 = (byte)0xFF;
63
64 assertTrue(ByteUtil.asUnsignedByte(b1) < ByteUtil.asUnsignedByte(b2));
65 assertTrue(ByteUtil.asUnsignedByte(b2) < ByteUtil.asUnsignedByte(b3));
66 assertTrue(ByteUtil.asUnsignedByte(b3) < ByteUtil.asUnsignedByte(b4));
67 assertTrue(ByteUtil.asUnsignedByte(b4) < ByteUtil.asUnsignedByte(b5));
68 }
69
70 public void testByteCodeComparator() {
71 byte[] b0 = null;
72 byte[] b1 = new byte[]{(byte)0x00};
73 byte[] b2 = new byte[]{(byte)0x00, (byte)0x00};
74 byte[] b3 = new byte[]{(byte)0x00, (byte)0x01};
75 byte[] b4 = new byte[]{(byte)0x01};
76 byte[] b5 = new byte[]{(byte)0x80};
77 byte[] b6 = new byte[]{(byte)0xFF};
78 byte[] b7 = new byte[]{(byte)0xFF, (byte)0x00};
79 byte[] b8 = new byte[]{(byte)0xFF, (byte)0x01};
80
81 List<byte[]> expectedList = Arrays.<byte[]>asList(b0, b1, b2, b3, b4,
82 b5, b6, b7, b8);
83 SortedSet<byte[]> sortedSet = new TreeSet<byte[]>(
84 Index.BYTE_CODE_COMPARATOR);
85 sortedSet.addAll(expectedList);
86 assertEquals(expectedList, new ArrayList<byte[]>(sortedSet));
87
88 }
89
90 public void testPrimaryKey() throws Exception {
91 Table table = open().getTable("Table1");
92 Map<String, Boolean> foundPKs = new HashMap<String, Boolean>();
93 for(Index index : table.getIndexes()) {
94 foundPKs.put(index.getColumns().iterator().next().getName(),
95 index.isPrimaryKey());
96 }
97 Map<String, Boolean> expectedPKs = new HashMap<String, Boolean>();
98 expectedPKs.put("A", Boolean.TRUE);
99 expectedPKs.put("B", Boolean.FALSE);
100 assertEquals(expectedPKs, foundPKs);
101 }
102
103 public void testIndexSlots() throws Exception
104 {
105 Database mdb = open(new File("test/data/indexTest.mdb"));
106
107 Table table = mdb.getTable("Table1");
108 for(Index idx : table.getIndexes()) {
109 idx.initialize();
110 }
111 assertEquals(4, table.getIndexes().size());
112 assertEquals(4, table.getIndexSlotCount());
113 checkIndexColumns(table,
114 "id", "id",
115 "PrimaryKey", "id",
116 "Table2Table1", "otherfk1",
117 "Table3Table1", "otherfk2");
118
119 table = mdb.getTable("Table2");
120 for(Index idx : table.getIndexes()) {
121 idx.initialize();
122 }
123 assertEquals(2, table.getIndexes().size());
124 assertEquals(3, table.getIndexSlotCount());
125 checkIndexColumns(table,
126 "id", "id",
127 "PrimaryKey", "id");
128
129 table = mdb.getTable("Table3");
130 for(Index idx : table.getIndexes()) {
131 idx.initialize();
132 }
133 assertEquals(2, table.getIndexes().size());
134 assertEquals(3, table.getIndexSlotCount());
135 checkIndexColumns(table,
136 "id", "id",
137 "PrimaryKey", "id");
138 }
139
140 public void testComplexIndex() throws Exception
141 {
142
143 File origFile = new File("test/data/compIndexTest.mdb");
144 Database db = open(origFile);
145 Table t = db.getTable("Table1");
146 Index index = t.getIndexes().get(0);
147 assertFalse(index.isInitialized());
148 assertEquals(512, countRows(t));
149 assertEquals(512, index.getEntryCount());
150 db.close();
151
152
153 db = openCopy(origFile);
154 t = db.getTable("Table1");
155 index = t.getIndexes().get(0);
156
157 System.out.println("IndexTest: Index type: " + index.getClass());
158 try {
159 t.addRow(99, "abc", "def");
160 if(index instanceof SimpleIndex) {
161
162 fail("Should have thrown UnsupportedOperationException");
163 }
164 } catch(UnsupportedOperationException e) {
165
166 if(index instanceof BigIndex) {
167 throw e;
168 }
169 }
170 }
171
172 public void testEntryDeletion() throws Exception {
173 Table table = openCopy(new File("test/data/test.mdb")).getTable("Table1");
174
175 for(int i = 0; i < 10; ++i) {
176 table.addRow("foo" + i, "bar" + i, (byte)42 + i, (short)53 + i, 13 * i,
177 (6.7d / i), null, null, true);
178 }
179 table.reset();
180 assertRowCount(12, table);
181
182 for(Index index : table.getIndexes()) {
183 assertEquals(12, index.getEntryCount());
184 }
185
186 table.reset();
187 table.getNextRow();
188 table.getNextRow();
189 table.deleteCurrentRow();
190 table.getNextRow();
191 table.deleteCurrentRow();
192 table.getNextRow();
193 table.getNextRow();
194 table.deleteCurrentRow();
195 table.getNextRow();
196 table.getNextRow();
197 table.getNextRow();
198 table.deleteCurrentRow();
199
200 table.reset();
201 assertRowCount(8, table);
202
203 for(Index index : table.getIndexes()) {
204 assertEquals(8, index.getEntryCount());
205 }
206 }
207
208 public void testIgnoreNulls() throws Exception
209 {
210 Database db = openCopy(new File("test/data/testIndexProperties.mdb"));
211
212 doTestIgnoreNulls(db, "TableIgnoreNulls1");
213 doTestIgnoreNulls(db, "TableIgnoreNulls2");
214
215 db.close();
216 }
217
218 private void doTestIgnoreNulls(Database db, String tableName)
219 throws Exception
220 {
221 Table orig = db.getTable(tableName);
222 Index origI = orig.getIndex("DataIndex");
223 Table temp = db.getTable(tableName + "_temp");
224 Index tempI = temp.getIndex("DataIndex");
225
226
227 for(Map<String,Object> row : orig) {
228 temp.addRow(orig.asRow(row));
229 }
230
231 assertEquals(origI.getEntryCount(), tempI.getEntryCount());
232
233 Cursor origC = Cursor.createIndexCursor(orig, origI);
234 Cursor tempC = Cursor.createIndexCursor(temp, tempI);
235
236 while(true) {
237 boolean origHasNext = origC.moveToNextRow();
238 boolean tempHasNext = tempC.moveToNextRow();
239 assertTrue(origHasNext == tempHasNext);
240 if(!origHasNext) {
241 break;
242 }
243
244 Map<String,Object> origRow = origC.getCurrentRow();
245 Cursor.Position origCurPos = origC.getSavepoint().getCurrentPosition();
246 Map<String,Object> tempRow = tempC.getCurrentRow();
247 Cursor.Position tempCurPos = tempC.getSavepoint().getCurrentPosition();
248
249 assertEquals(origRow, tempRow);
250 assertEquals(IndexCodesTest.entryToString(origCurPos),
251 IndexCodesTest.entryToString(tempCurPos));
252 }
253 }
254
255 public void testUnique() throws Exception
256 {
257 Database db = openCopy(new File("test/data/testIndexProperties.mdb"));
258
259 Table t = db.getTable("TableUnique1_temp");
260 Index index = t.getIndex("DataIndex");
261
262 doTestUnique(t, index, 1,
263 null, true,
264 "unique data", true,
265 null, true,
266 "more", false,
267 "stuff", false,
268 "unique data", false);
269
270 t = db.getTable("TableUnique2_temp");
271 index = t.getIndex("DataIndex");
272
273 doTestUnique(t, index, 2,
274 null, null, true,
275 "unique data", 42, true,
276 "unique data", null, true,
277 null, null, true,
278 "some", 42, true,
279 "more unique data", 13, true,
280 null, -4242, true,
281 "another row", -3462, false,
282 null, 49, false,
283 "more", null, false,
284 "unique data", 42, false,
285 "unique data", null, false,
286 null, -4242, false);
287
288 db.close();
289 }
290
291 private void doTestUnique(Table t, Index index, int numValues,
292 Object... testData)
293 throws Exception
294 {
295 for(int i = 0; i < testData.length; i += (numValues + 1)) {
296 Object[] row = new Object[numValues + 1];
297 row[0] = "testRow" + i;
298 for(int j = 1; j < (numValues + 1); ++j) {
299 row[j] = testData[i + j - 1];
300 }
301 boolean expectedSuccess = (Boolean)testData[i + numValues];
302
303 IOException failure = null;
304 try {
305 index.addRow(row, new RowId(400 + i, 0));
306 } catch(IOException e) {
307 failure = e;
308 }
309 if(expectedSuccess) {
310 assertNull(failure);
311 } else {
312 assertTrue(failure != null);
313 assertTrue(failure.getMessage().contains("uniqueness"));
314 }
315 }
316 }
317
318 public void testUniqueEntryCount() throws Exception {
319 Database db = openCopy(new File("test/data/test.mdb"));
320 Table table = db.getTable("Table1");
321 Index indA = table.getIndex("PrimaryKey");
322 Index indB = table.getIndex("B");
323
324 assertEquals(2, indA.getUniqueEntryCount());
325 assertEquals(2, indB.getUniqueEntryCount());
326
327 List<String> bElems = Arrays.asList("bar", null, "baz", "argle", null,
328 "bazzle", "37", "bar", "bar", "BAZ");
329
330 for(int i = 0; i < 10; ++i) {
331 table.addRow("foo" + i, bElems.get(i), (byte)42 + i, (short)53 + i,
332 13 * i, (6.7d / i), null, null, true);
333 }
334
335 assertEquals(12, indA.getEntryCount());
336 assertEquals(12, indB.getEntryCount());
337
338 assertEquals(12, indA.getUniqueEntryCount());
339 assertEquals(8, indB.getUniqueEntryCount());
340
341 table = null;
342 indA = null;
343 indB = null;
344
345 table = db.getTable("Table1");
346 indA = table.getIndex("PrimaryKey");
347 indB = table.getIndex("B");
348
349 assertEquals(12, indA.getEntryCount());
350 assertEquals(12, indB.getEntryCount());
351
352 assertEquals(12, indA.getUniqueEntryCount());
353 assertEquals(8, indB.getUniqueEntryCount());
354
355 Cursor c = Cursor.createCursor(table);
356 assertTrue(c.moveToNextRow());
357 Map<String,Object> row = c.getCurrentRow();
358 assertEquals("abcdefg", row.get("A"));
359 assertEquals("hijklmnop", row.get("B"));
360 c.deleteCurrentRow();
361
362 assertEquals(11, indA.getEntryCount());
363 assertEquals(11, indB.getEntryCount());
364
365 assertEquals(12, indA.getUniqueEntryCount());
366 assertEquals(8, indB.getUniqueEntryCount());
367
368 db.close();
369 }
370
371 private void checkIndexColumns(Table table, String... idxInfo)
372 throws Exception
373 {
374 Map<String, String> expectedIndexes = new HashMap<String, String>();
375 for(int i = 0; i < idxInfo.length; i+=2) {
376 expectedIndexes.put(idxInfo[i], idxInfo[i+1]);
377 }
378
379 for(Index idx : table.getIndexes()) {
380 String colName = expectedIndexes.get(idx.getName());
381 assertEquals(1, idx.getColumns().size());
382 assertEquals(colName, idx.getColumns().get(0).getName());
383 if("PrimaryKey".equals(idx.getName())) {
384 assertTrue(idx.isPrimaryKey());
385 } else {
386 assertFalse(idx.isPrimaryKey());
387 }
388 }
389 }
390
391 }