View Javadoc
1   /*
2   Copyright (c) 2015 James Ahlborn
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess.impl;
18  
19  import java.io.IOException;
20  import java.util.Collections;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.UUID;
24  
25  import com.healthmarketscience.jackcess.Column;
26  import com.healthmarketscience.jackcess.ColumnBuilder;
27  import com.healthmarketscience.jackcess.CursorBuilder;
28  import com.healthmarketscience.jackcess.DataType;
29  import com.healthmarketscience.jackcess.Database;
30  import static com.healthmarketscience.jackcess.Database.*;
31  import com.healthmarketscience.jackcess.Row;
32  import com.healthmarketscience.jackcess.Table;
33  import com.healthmarketscience.jackcess.TableBuilder;
34  import static com.healthmarketscience.jackcess.TestUtil.*;
35  import com.healthmarketscience.jackcess.complex.ComplexValueForeignKey;
36  import static com.healthmarketscience.jackcess.impl.JetFormatTest.*;
37  import junit.framework.TestCase;
38  
39  /**
40   *
41   * @author James Ahlborn
42   */
43  public class AutoNumberTest extends TestCase
44  {
45  
46    public AutoNumberTest(String name) throws Exception {
47      super(name);
48    }
49  
50  
51    public void testAutoNumber() throws Exception 
52    {
53      for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
54        Database db = createMem(fileFormat);
55  
56        Table table = new TableBuilder("test")
57          .addColumn(new ColumnBuilder("a", DataType.LONG)
58                    .setAutoNumber(true))
59          .addColumn(new ColumnBuilder("b", DataType.TEXT))
60          .toTable(db);
61  
62        doTestAutoNumber(table);
63  
64        db.close();
65      }
66    }  
67  
68    public void testAutoNumberPK() throws Exception 
69    {
70      for (final TestDB testDB : SUPPORTED_DBS_TEST) {
71        Database db = openMem(testDB);
72  
73        Table table = db.getTable("Table3");
74  
75        doTestAutoNumber(table);
76  
77        db.close();
78      }
79    }  
80  
81    private static void doTestAutoNumber(Table table) throws Exception
82    {
83      Object[] row = {null, "row1"};
84      assertSame(row, table.addRow(row));
85      assertEquals(1, ((Integer)row[0]).intValue());
86      row = table.addRow(13, "row2");
87      assertEquals(2, ((Integer)row[0]).intValue());
88      row = table.addRow("flubber", "row3");
89      assertEquals(3, ((Integer)row[0]).intValue());
90  
91      table.reset();
92  
93      row = table.addRow(Column.AUTO_NUMBER, "row4");
94      assertEquals(4, ((Integer)row[0]).intValue());
95      row = table.addRow(Column.AUTO_NUMBER, "row5");
96      assertEquals(5, ((Integer)row[0]).intValue());
97  
98      Object[] smallRow = {Column.AUTO_NUMBER};
99      row = table.addRow(smallRow);
100     assertNotSame(row, smallRow);
101     assertEquals(6, ((Integer)row[0]).intValue());    
102 
103     table.reset();
104 
105     List<? extends Map<String, Object>> expectedRows =
106       createExpectedTable(
107           createExpectedRow(
108               "a", 1,
109               "b", "row1"),
110           createExpectedRow(
111               "a", 2,
112               "b", "row2"),
113           createExpectedRow(
114               "a", 3,
115               "b", "row3"),
116           createExpectedRow(
117               "a", 4,
118               "b", "row4"),
119           createExpectedRow(
120               "a", 5,
121               "b", "row5"),
122           createExpectedRow(
123               "a", 6,
124               "b", null));
125 
126     assertTable(expectedRows, table);    
127   }
128 
129   public void testAutoNumberGuid() throws Exception 
130   {
131     for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
132       Database db = createMem(fileFormat);
133 
134       Table table = new TableBuilder("test")
135         .addColumn(new ColumnBuilder("a", DataType.GUID)
136                   .setAutoNumber(true))
137         .addColumn(new ColumnBuilder("b", DataType.TEXT))
138         .toTable(db);
139 
140       Object[] row = {null, "row1"};
141       assertSame(row, table.addRow(row));
142       assertTrue(ColumnImpl.isGUIDValue(row[0]));
143       row = table.addRow(13, "row2");
144       assertTrue(ColumnImpl.isGUIDValue(row[0]));
145       row = table.addRow("flubber", "row3");
146       assertTrue(ColumnImpl.isGUIDValue(row[0]));
147 
148       Object[] smallRow = {Column.AUTO_NUMBER};
149       row = table.addRow(smallRow);
150       assertNotSame(row, smallRow);
151       assertTrue(ColumnImpl.isGUIDValue(row[0]));
152 
153       db.close();
154     }
155   }  
156 
157   public void testInsertLongAutoNumber() throws Exception
158   {
159     for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
160       Database db = createMem(fileFormat);
161 
162       Table table = new TableBuilder("test")
163         .addColumn(new ColumnBuilder("a", DataType.LONG)
164                   .setAutoNumber(true))
165         .addColumn(new ColumnBuilder("b", DataType.TEXT))
166         .toTable(db);
167 
168       doTestInsertLongAutoNumber(table);
169 
170       db.close();
171     }    
172   }
173 
174   public void testInsertLongAutoNumberPK() throws Exception
175   {
176     for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
177       Database db = createMem(fileFormat);
178 
179       Table table = new TableBuilder("test")
180         .addColumn(new ColumnBuilder("a", DataType.LONG)
181                   .setAutoNumber(true))
182         .addColumn(new ColumnBuilder("b", DataType.TEXT))
183         .setPrimaryKey("a")
184         .toTable(db);
185 
186       doTestInsertLongAutoNumber(table);
187 
188       db.close();
189     }    
190   }
191 
192   private static void doTestInsertLongAutoNumber(Table table) throws Exception
193   {
194     assertFalse(table.getDatabase().isAllowAutoNumberInsert());
195     assertFalse(table.isAllowAutoNumberInsert());
196 
197     Object[] row = {null, "row1"};
198     assertSame(row, table.addRow(row));
199     assertEquals(1, ((Integer)row[0]).intValue());
200     row = table.addRow(13, "row2");
201     assertEquals(2, ((Integer)row[0]).intValue());
202     row = table.addRow("flubber", "row3");
203     assertEquals(3, ((Integer)row[0]).intValue());
204 
205     table.reset();
206 
207     table.setAllowAutoNumberInsert(true);
208     assertFalse(table.getDatabase().isAllowAutoNumberInsert());
209     assertTrue(table.isAllowAutoNumberInsert());
210 
211     Row row2 = CursorBuilder.findRow(
212         table, Collections.singletonMap("a", 2));
213     assertEquals("row2", row2.getString("b"));
214 
215     table.deleteRow(row2);
216 
217     row = table.addRow(Column.AUTO_NUMBER, "row4");
218     assertEquals(4, ((Integer)row[0]).intValue());
219 
220     assertEquals(4, ((TableImpl)table).getLastLongAutoNumber());
221 
222     row = table.addRow(2, "row2-redux");
223     assertEquals(2, ((Integer)row[0]).intValue());
224 
225     assertEquals(4, ((TableImpl)table).getLastLongAutoNumber());
226 
227     row2 = CursorBuilder.findRow(
228         table, Collections.singletonMap("a", 2));
229     assertEquals("row2-redux", row2.getString("b"));
230 
231     row = table.addRow(13, "row13-mindthegap");
232     assertEquals(13, ((Integer)row[0]).intValue());
233 
234     assertEquals(13, ((TableImpl)table).getLastLongAutoNumber());
235     
236     try {
237       table.addRow("not a number", "nope");
238       fail("NumberFormatException should have been thrown");
239     } catch(NumberFormatException e) {
240       // success
241     }
242 
243     assertEquals(13, ((TableImpl)table).getLastLongAutoNumber());
244 
245     try {
246       table.addRow(-10, "uh-uh");
247       fail("IOException should have been thrown");
248     } catch(IOException e) {
249       // success
250     }
251 
252     row = table.addRow(Column.AUTO_NUMBER, "row14");
253     assertEquals(14, ((Integer)row[0]).intValue());
254 
255     Row row13 = CursorBuilder.findRow(
256         table, Collections.singletonMap("a", 13));
257     assertEquals("row13-mindthegap", row13.getString("b"));
258 
259     row13.put("a", "45");
260     row13 = table.updateRow(row13);
261     assertEquals(45, row13.get("a"));
262 
263     assertEquals(45, ((TableImpl)table).getLastLongAutoNumber());
264 
265     row13.put("a", -1);
266 
267     try {
268       table.updateRow(row13);
269       fail("IOException should have been thrown");
270     } catch(IOException e) {
271       // success
272     }
273 
274     assertEquals(45, ((TableImpl)table).getLastLongAutoNumber());
275 
276     row13.put("a", 55);
277 
278     table.setAllowAutoNumberInsert(null);
279 
280     row13 = table.updateRow(row13);
281     assertEquals(45, row13.get("a"));
282 
283     assertEquals(45, ((TableImpl)table).getLastLongAutoNumber());
284     
285   }
286 
287   public void testInsertComplexAutoNumber() throws Exception
288   {
289     for(final TestDB testDB : TestDB.getSupportedForBasename(Basename.COMPLEX)) {
290       
291       Database db = openMem(testDB);
292 
293       Table t1 = db.getTable("Table1");
294 
295       assertFalse(t1.isAllowAutoNumberInsert());
296 
297       int lastAutoNum = ((TableImpl)t1).getLastComplexTypeAutoNumber();
298 
299       Object[] row = t1.addRow("arow");
300       ++lastAutoNum;
301       checkAllComplexAutoNums(lastAutoNum, row);
302 
303       assertEquals(lastAutoNum, ((TableImpl)t1).getLastComplexTypeAutoNumber());
304 
305       db.setAllowAutoNumberInsert(true);
306       assertTrue(db.isAllowAutoNumberInsert());
307       assertTrue(t1.isAllowAutoNumberInsert());
308 
309       row = t1.addRow("anotherrow");
310       ++lastAutoNum;
311       checkAllComplexAutoNums(lastAutoNum, row);
312 
313       assertEquals(lastAutoNum, ((TableImpl)t1).getLastComplexTypeAutoNumber());
314       
315       row = t1.addRow("row5", 5, null, null, 5, 5);
316       checkAllComplexAutoNums(5, row);
317 
318       assertEquals(lastAutoNum, ((TableImpl)t1).getLastComplexTypeAutoNumber());
319 
320       row = t1.addRow("row13", 13, null, null, 13, 13);
321       checkAllComplexAutoNums(13, row);
322 
323       assertEquals(13, ((TableImpl)t1).getLastComplexTypeAutoNumber());
324 
325       try {
326         t1.addRow("nope", "not a number");
327         fail("NumberFormatException should have been thrown");
328       } catch(NumberFormatException e) {
329         // success
330       }
331 
332       assertEquals(13, ((TableImpl)t1).getLastComplexTypeAutoNumber());
333 
334       try {
335         t1.addRow("uh-uh", -10);
336         fail("IOException should have been thrown");
337       } catch(IOException e) {
338         // success
339       }
340 
341       assertEquals(13, ((TableImpl)t1).getLastComplexTypeAutoNumber());
342 
343       try {
344         t1.addRow("wut", 6, null, null, 40, 42);
345         fail("IOException should have been thrown");
346       } catch(IOException e) {
347         // success
348       }
349 
350       row = t1.addRow("morerows");
351       checkAllComplexAutoNums(14, row);
352 
353       assertEquals(14, ((TableImpl)t1).getLastComplexTypeAutoNumber());
354       
355       Row row13 = CursorBuilder.findRow(
356           t1, Collections.singletonMap("id", "row13"));
357 
358       row13.put("VersionHistory_F5F8918F-0A3F-4DA9-AE71-184EE5012880", "45");
359       row13.put("multi-value-data", "45");
360       row13.put("attach-data", "45");
361       row13 = t1.updateRow(row13);
362       checkAllComplexAutoNums(45, row13);
363 
364       assertEquals(45, ((TableImpl)t1).getLastComplexTypeAutoNumber());
365       
366       row13.put("attach-data", -1);
367 
368       try {
369         t1.updateRow(row13);
370         fail("IOException should have been thrown");
371       } catch(IOException e) {
372         // success
373       }
374 
375       assertEquals(45, ((TableImpl)t1).getLastComplexTypeAutoNumber());
376 
377       row13.put("attach-data", 55);
378 
379       try {
380         t1.updateRow(row13);
381         fail("IOException should have been thrown");
382       } catch(IOException e) {
383         // success
384       }
385 
386       assertEquals(45, ((TableImpl)t1).getLastComplexTypeAutoNumber());
387 
388       row13.put("VersionHistory_F5F8918F-0A3F-4DA9-AE71-184EE5012880", 55);
389       row13.put("multi-value-data", 55);
390 
391       db.setAllowAutoNumberInsert(null);
392 
393       row13 = t1.updateRow(row13);
394       checkAllComplexAutoNums(45, row13);
395 
396       assertEquals(45, ((TableImpl)t1).getLastComplexTypeAutoNumber());
397 
398       db.close();
399     }
400   }
401 
402   private static void checkAllComplexAutoNums(int expected, Object[] row)
403   {
404     assertEquals(expected, ((ComplexValueForeignKey)row[1]).get());
405     assertEquals(expected, ((ComplexValueForeignKey)row[4]).get());
406     assertEquals(expected, ((ComplexValueForeignKey)row[5]).get());
407   }
408 
409   private static void checkAllComplexAutoNums(int expected, Row row)
410   {
411       assertEquals(expected, ((Number)row.get("VersionHistory_F5F8918F-0A3F-4DA9-AE71-184EE5012880")).intValue());
412       assertEquals(expected, ((Number)row.get("multi-value-data")).intValue());
413       assertEquals(expected, ((Number)row.get("attach-data")).intValue());
414   }
415 
416   public void testInsertGuidAutoNumber() throws Exception 
417   {
418     for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
419       Database db = createMem(fileFormat);
420 
421       Table table = new TableBuilder("test")
422         .addColumn(new ColumnBuilder("a", DataType.GUID)
423                   .setAutoNumber(true))
424         .addColumn(new ColumnBuilder("b", DataType.TEXT))
425         .toTable(db);
426 
427       db.setAllowAutoNumberInsert(true);
428       table.setAllowAutoNumberInsert(false);
429       assertFalse(table.isAllowAutoNumberInsert());
430 
431       Object[] row = {null, "row1"};
432       assertSame(row, table.addRow(row));
433       assertTrue(ColumnImpl.isGUIDValue(row[0]));
434       row = table.addRow(13, "row2");
435       assertTrue(ColumnImpl.isGUIDValue(row[0]));
436       row = table.addRow("flubber", "row3");
437       assertTrue(ColumnImpl.isGUIDValue(row[0]));
438 
439       Object[] smallRow = {Column.AUTO_NUMBER};
440       row = table.addRow(smallRow);
441       assertNotSame(row, smallRow);
442       assertTrue(ColumnImpl.isGUIDValue(row[0]));
443 
444       table.setAllowAutoNumberInsert(null);
445       assertTrue(table.isAllowAutoNumberInsert());
446       
447       Row row2 = CursorBuilder.findRow(
448           table, Collections.singletonMap("b", "row2"));
449       assertEquals("row2", row2.getString("b"));
450       
451       String row2Guid = row2.getString("a");
452       table.deleteRow(row2);
453 
454       row = table.addRow(Column.AUTO_NUMBER, "row4");
455       assertTrue(ColumnImpl.isGUIDValue(row[0]));
456 
457       row = table.addRow(row2Guid, "row2-redux");
458       assertEquals(row2Guid, row[0]);
459 
460       row2 = CursorBuilder.findRow(
461           table, Collections.singletonMap("a", row2Guid));
462       assertEquals("row2-redux", row2.getString("b"));
463 
464       try {
465         table.addRow("not a guid", "nope");
466         fail("IOException should have been thrown");
467       } catch(IOException e) {
468         // success
469       }
470 
471       row = table.addRow(Column.AUTO_NUMBER, "row5");
472       assertTrue(ColumnImpl.isGUIDValue(row[0]));
473 
474       row2Guid = UUID.randomUUID().toString();
475       row2.put("a", row2Guid);
476 
477       row2 = table.updateRow(row2);
478       assertEquals(row2Guid, row2.get("a"));
479 
480       row2.put("a", "not a guid");
481 
482       try {
483         table.updateRow(row2);
484         fail("IOException should have been thrown");
485       } catch(IOException e) {
486         // success
487       }
488 
489       table.setAllowAutoNumberInsert(false);
490 
491       row2 = table.updateRow(row2);
492       assertTrue(ColumnImpl.isGUIDValue(row2.get("a")));
493       assertFalse(row2Guid.equals(row2.get("a")));
494 
495       db.close();
496     }
497   }  
498 
499 }