You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DatabaseTest.java 32KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. /*
  2. Copyright (c) 2007 Health Market Science, Inc.
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with this library; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  14. USA
  15. You can contact Health Market Science at info@healthmarketscience.com
  16. or at the following address:
  17. Health Market Science
  18. 2700 Horizon Drive
  19. Suite 200
  20. King of Prussia, PA 19406
  21. */
  22. package com.healthmarketscience.jackcess;
  23. import java.io.File;
  24. import java.io.FileInputStream;
  25. import java.io.FileNotFoundException;
  26. import java.io.FileOutputStream;
  27. import java.io.IOException;
  28. import java.io.InputStream;
  29. import java.io.OutputStream;
  30. import java.io.PrintWriter;
  31. import java.math.BigDecimal;
  32. import java.nio.ByteBuffer;
  33. import java.sql.Types;
  34. import java.text.DateFormat;
  35. import java.text.SimpleDateFormat;
  36. import java.util.ArrayList;
  37. import java.util.Arrays;
  38. import java.util.Calendar;
  39. import java.util.Collections;
  40. import java.util.Date;
  41. import java.util.HashSet;
  42. import java.util.Iterator;
  43. import java.util.LinkedHashMap;
  44. import java.util.List;
  45. import java.util.Map;
  46. import java.util.Set;
  47. import java.util.UUID;
  48. import junit.framework.TestCase;
  49. /**
  50. * @author Tim McCune
  51. */
  52. public class DatabaseTest extends TestCase {
  53. static boolean _autoSync = Database.DEFAULT_AUTO_SYNC;
  54. public DatabaseTest(String name) throws Exception {
  55. super(name);
  56. }
  57. static Database open() throws Exception {
  58. return open(new File("test/data/test.mdb"));
  59. }
  60. static Database open(File file) throws Exception {
  61. return Database.open(file, true, _autoSync);
  62. }
  63. static Database create() throws Exception {
  64. return create(false);
  65. }
  66. static Database create(boolean keep) throws Exception {
  67. return Database.create(createTempFile(keep), _autoSync);
  68. }
  69. static Database openCopy(File srcFile) throws Exception {
  70. return openCopy(srcFile, false);
  71. }
  72. static Database openCopy(File srcFile, boolean keep) throws Exception {
  73. File tmp = createTempFile(keep);
  74. copyFile(srcFile, tmp);
  75. return Database.open(tmp, false, _autoSync);
  76. }
  77. public void testInvalidTableDefs() throws Exception {
  78. Database db = create();
  79. try {
  80. db.createTable("test", Collections.<Column>emptyList());
  81. fail("created table with no columns?");
  82. } catch(IllegalArgumentException e) {
  83. // success
  84. }
  85. try {
  86. new TableBuilder("test")
  87. .addColumn(new ColumnBuilder("A", DataType.TEXT).toColumn())
  88. .addColumn(new ColumnBuilder("a", DataType.MEMO).toColumn())
  89. .toTable(db);
  90. fail("created table with duplicate column names?");
  91. } catch(IllegalArgumentException e) {
  92. // success
  93. }
  94. try {
  95. new TableBuilder("test")
  96. .addColumn(new ColumnBuilder("A", DataType.TEXT)
  97. .setLengthInUnits(352).toColumn())
  98. .toTable(db);
  99. fail("created table with invalid column length?");
  100. } catch(IllegalArgumentException e) {
  101. // success
  102. }
  103. try {
  104. new TableBuilder("test")
  105. .addColumn(new ColumnBuilder("A_" + createString(70), DataType.TEXT)
  106. .toColumn())
  107. .toTable(db);
  108. fail("created table with too long column name?");
  109. } catch(IllegalArgumentException e) {
  110. // success
  111. }
  112. new TableBuilder("test")
  113. .addColumn(new ColumnBuilder("A", DataType.TEXT).toColumn())
  114. .toTable(db);
  115. try {
  116. new TableBuilder("Test")
  117. .addColumn(new ColumnBuilder("A", DataType.TEXT).toColumn())
  118. .toTable(db);
  119. fail("create duplicate tables?");
  120. } catch(IllegalArgumentException e) {
  121. // success
  122. }
  123. }
  124. public void testReadDeletedRows() throws Exception {
  125. Table table = open(new File("test/data/delTest.mdb")).getTable("Table");
  126. int rows = 0;
  127. while (table.getNextRow() != null) {
  128. rows++;
  129. }
  130. assertEquals(2, rows);
  131. }
  132. public void testGetColumns() throws Exception {
  133. List columns = open().getTable("Table1").getColumns();
  134. assertEquals(9, columns.size());
  135. checkColumn(columns, 0, "A", DataType.TEXT);
  136. checkColumn(columns, 1, "B", DataType.TEXT);
  137. checkColumn(columns, 2, "C", DataType.BYTE);
  138. checkColumn(columns, 3, "D", DataType.INT);
  139. checkColumn(columns, 4, "E", DataType.LONG);
  140. checkColumn(columns, 5, "F", DataType.DOUBLE);
  141. checkColumn(columns, 6, "G", DataType.SHORT_DATE_TIME);
  142. checkColumn(columns, 7, "H", DataType.MONEY);
  143. checkColumn(columns, 8, "I", DataType.BOOLEAN);
  144. }
  145. static void checkColumn(List columns, int columnNumber, String name,
  146. DataType dataType)
  147. throws Exception
  148. {
  149. Column column = (Column) columns.get(columnNumber);
  150. assertEquals(name, column.getName());
  151. assertEquals(dataType, column.getType());
  152. }
  153. public void testGetNextRow() throws Exception {
  154. Database db = open();
  155. assertEquals(3, db.getTableNames().size());
  156. Table table = db.getTable("Table1");
  157. Map<String, Object> row = table.getNextRow();
  158. assertEquals("abcdefg", row.get("A"));
  159. assertEquals("hijklmnop", row.get("B"));
  160. assertEquals(new Byte((byte) 2), row.get("C"));
  161. assertEquals(new Short((short) 222), row.get("D"));
  162. assertEquals(new Integer(333333333), row.get("E"));
  163. assertEquals(new Double(444.555d), row.get("F"));
  164. Calendar cal = Calendar.getInstance();
  165. cal.setTime((Date) row.get("G"));
  166. assertEquals(Calendar.SEPTEMBER, cal.get(Calendar.MONTH));
  167. assertEquals(21, cal.get(Calendar.DAY_OF_MONTH));
  168. assertEquals(1974, cal.get(Calendar.YEAR));
  169. assertEquals(0, cal.get(Calendar.HOUR_OF_DAY));
  170. assertEquals(0, cal.get(Calendar.MINUTE));
  171. assertEquals(0, cal.get(Calendar.SECOND));
  172. assertEquals(0, cal.get(Calendar.MILLISECOND));
  173. assertEquals(Boolean.TRUE, row.get("I"));
  174. row = table.getNextRow();
  175. assertEquals("a", row.get("A"));
  176. assertEquals("b", row.get("B"));
  177. assertEquals(new Byte((byte) 0), row.get("C"));
  178. assertEquals(new Short((short) 0), row.get("D"));
  179. assertEquals(new Integer(0), row.get("E"));
  180. assertEquals(new Double(0d), row.get("F"));
  181. cal = Calendar.getInstance();
  182. cal.setTime((Date) row.get("G"));
  183. assertEquals(Calendar.DECEMBER, cal.get(Calendar.MONTH));
  184. assertEquals(12, cal.get(Calendar.DAY_OF_MONTH));
  185. assertEquals(1981, cal.get(Calendar.YEAR));
  186. assertEquals(0, cal.get(Calendar.HOUR_OF_DAY));
  187. assertEquals(0, cal.get(Calendar.MINUTE));
  188. assertEquals(0, cal.get(Calendar.SECOND));
  189. assertEquals(0, cal.get(Calendar.MILLISECOND));
  190. assertEquals(Boolean.FALSE, row.get("I"));
  191. }
  192. public void testCreate() throws Exception {
  193. Database db = create();
  194. assertEquals(0, db.getTableNames().size());
  195. }
  196. public void testWriteAndRead() throws Exception {
  197. Database db = create();
  198. createTestTable(db);
  199. Object[] row = createTestRow();
  200. row[3] = null;
  201. Table table = db.getTable("Test");
  202. int count = 1000;
  203. for (int i = 0; i < count; i++) {
  204. table.addRow(row);
  205. }
  206. for (int i = 0; i < count; i++) {
  207. Map<String, Object> readRow = table.getNextRow();
  208. assertEquals(row[0], readRow.get("A"));
  209. assertEquals(row[1], readRow.get("B"));
  210. assertEquals(row[2], readRow.get("C"));
  211. assertEquals(row[3], readRow.get("D"));
  212. assertEquals(row[4], readRow.get("E"));
  213. assertEquals(row[5], readRow.get("F"));
  214. assertEquals(row[6], readRow.get("G"));
  215. assertEquals(row[7], readRow.get("H"));
  216. }
  217. }
  218. public void testWriteAndReadInBatch() throws Exception {
  219. Database db = create();
  220. createTestTable(db);
  221. int count = 1000;
  222. List<Object[]> rows = new ArrayList<Object[]>(count);
  223. Object[] row = createTestRow();
  224. for (int i = 0; i < count; i++) {
  225. rows.add(row);
  226. }
  227. Table table = db.getTable("Test");
  228. table.addRows(rows);
  229. for (int i = 0; i < count; i++) {
  230. Map<String, Object> readRow = table.getNextRow();
  231. assertEquals(row[0], readRow.get("A"));
  232. assertEquals(row[1], readRow.get("B"));
  233. assertEquals(row[2], readRow.get("C"));
  234. assertEquals(row[3], readRow.get("D"));
  235. assertEquals(row[4], readRow.get("E"));
  236. assertEquals(row[5], readRow.get("F"));
  237. assertEquals(row[6], readRow.get("G"));
  238. assertEquals(row[7], readRow.get("H"));
  239. }
  240. }
  241. public void testDeleteCurrentRow() throws Exception {
  242. // make sure correct row is deleted
  243. Database db = create();
  244. createTestTable(db);
  245. Object[] row1 = createTestRow("Tim1");
  246. Object[] row2 = createTestRow("Tim2");
  247. Object[] row3 = createTestRow("Tim3");
  248. Table table = db.getTable("Test");
  249. table.addRows(Arrays.asList(row1, row2, row3));
  250. assertRowCount(3, table);
  251. table.reset();
  252. table.getNextRow();
  253. table.getNextRow();
  254. table.deleteCurrentRow();
  255. table.reset();
  256. Map<String, Object> outRow = table.getNextRow();
  257. assertEquals("Tim1", outRow.get("A"));
  258. outRow = table.getNextRow();
  259. assertEquals("Tim3", outRow.get("A"));
  260. assertRowCount(2, table);
  261. // test multi row delete/add
  262. db = create();
  263. createTestTable(db);
  264. Object[] row = createTestRow();
  265. table = db.getTable("Test");
  266. for (int i = 0; i < 10; i++) {
  267. row[3] = i;
  268. table.addRow(row);
  269. }
  270. row[3] = 1974;
  271. assertRowCount(10, table);
  272. table.reset();
  273. table.getNextRow();
  274. table.deleteCurrentRow();
  275. assertRowCount(9, table);
  276. table.reset();
  277. table.getNextRow();
  278. table.deleteCurrentRow();
  279. assertRowCount(8, table);
  280. table.reset();
  281. for (int i = 0; i < 8; i++) {
  282. table.getNextRow();
  283. }
  284. table.deleteCurrentRow();
  285. assertRowCount(7, table);
  286. table.addRow(row);
  287. assertRowCount(8, table);
  288. table.reset();
  289. for (int i = 0; i < 3; i++) {
  290. table.getNextRow();
  291. }
  292. table.deleteCurrentRow();
  293. assertRowCount(7, table);
  294. table.reset();
  295. assertEquals(2, table.getNextRow().get("D"));
  296. }
  297. public void testReadLongValue() throws Exception {
  298. Database db = open(new File("test/data/test2.mdb"));
  299. Table table = db.getTable("MSP_PROJECTS");
  300. Map<String, Object> row = table.getNextRow();
  301. assertEquals("Jon Iles this is a a vawesrasoih aksdkl fas dlkjflkasjd flkjaslkdjflkajlksj dfl lkasjdf lkjaskldfj lkas dlk lkjsjdfkl; aslkdf lkasjkldjf lka skldf lka sdkjfl;kasjd falksjdfljaslkdjf laskjdfk jalskjd flkj aslkdjflkjkjasljdflkjas jf;lkasjd fjkas dasdf asd fasdf asdf asdmhf lksaiyudfoi jasodfj902384jsdf9 aw90se fisajldkfj lkasj dlkfslkd jflksjadf as", row.get("PROJ_PROP_AUTHOR"));
  302. assertEquals("T", row.get("PROJ_PROP_COMPANY"));
  303. assertEquals("Standard", row.get("PROJ_INFO_CAL_NAME"));
  304. assertEquals("Project1", row.get("PROJ_PROP_TITLE"));
  305. byte[] foundBinaryData = (byte[])row.get("RESERVED_BINARY_DATA");
  306. byte[] expectedBinaryData =
  307. toByteArray(new File("test/data/test2BinData.dat"));
  308. assertTrue(Arrays.equals(expectedBinaryData, foundBinaryData));
  309. }
  310. public void testWriteLongValue() throws Exception {
  311. Database db = create();
  312. Table table =
  313. new TableBuilder("test")
  314. .addColumn(new ColumnBuilder("A", DataType.TEXT).toColumn())
  315. .addColumn(new ColumnBuilder("B", DataType.MEMO).toColumn())
  316. .addColumn(new ColumnBuilder("C", DataType.OLE).toColumn())
  317. .toTable(db);
  318. String testStr = "This is a test";
  319. String longMemo = createString(2030);
  320. byte[] oleValue = toByteArray(new File("test/data/test2BinData.dat"));
  321. table.addRow(testStr, testStr, null);
  322. table.addRow(testStr, longMemo, oleValue);
  323. table.reset();
  324. Map<String, Object> row = table.getNextRow();
  325. assertEquals(testStr, row.get("A"));
  326. assertEquals(testStr, row.get("B"));
  327. assertNull(row.get("C"));
  328. row = table.getNextRow();
  329. assertEquals(testStr, row.get("A"));
  330. assertEquals(longMemo, row.get("B"));
  331. assertTrue(Arrays.equals(oleValue, (byte[])row.get("C")));
  332. }
  333. public void testManyMemos() throws Exception {
  334. final int numColumns = 126;
  335. Database db = create();
  336. TableBuilder bigTableBuilder = new TableBuilder("test");
  337. for (int i = 0; i < numColumns; i++)
  338. {
  339. Column column = new ColumnBuilder("column_" + i, DataType.MEMO)
  340. .toColumn();
  341. bigTableBuilder.addColumn(column);
  342. }
  343. Table bigTable = bigTableBuilder.toTable(db);
  344. List<Object[]> expectedRows = new ArrayList<Object[]>();
  345. for (int j = 0; j < 3; j++)
  346. {
  347. Object[] rowData = new String[numColumns];
  348. for (int i = 0; i < numColumns; i++)
  349. {
  350. rowData[i] = "v_" + i + ";" + (j + 999);
  351. }
  352. expectedRows.add(rowData);
  353. bigTable.addRow(rowData);
  354. }
  355. String extra1 = createString(100);
  356. String extra2 = createString(2050);
  357. for (int j = 0; j < 1; j++)
  358. {
  359. Object[] rowData = new String[numColumns];
  360. for (int i = 0; i < numColumns; i++)
  361. {
  362. rowData[i] = "v_" + i + ";" + (j + 999) + extra2;
  363. }
  364. expectedRows.add(rowData);
  365. bigTable.addRow(rowData);
  366. }
  367. for (int j = 0; j < 2; j++)
  368. {
  369. Object[] rowData = new String[numColumns];
  370. for (int i = 0; i < numColumns; i++)
  371. {
  372. String tmp = "v_" + i + ";" + (j + 999);
  373. if((i % 3) == 0) {
  374. tmp += extra1;
  375. } else if((i % 7) == 0) {
  376. tmp += extra2;
  377. }
  378. rowData[i] = tmp;
  379. }
  380. expectedRows.add(rowData);
  381. bigTable.addRow(rowData);
  382. }
  383. bigTable.reset();
  384. Iterator<Object[]> expIter = expectedRows.iterator();
  385. for(Map<?,?> row : bigTable) {
  386. Object[] expectedRow = expIter.next();
  387. assertEquals(Arrays.asList(expectedRow),
  388. new ArrayList<Object>(row.values()));
  389. }
  390. db.close();
  391. }
  392. public void testMissingFile() throws Exception {
  393. File bogusFile = new File("fooby-dooby.mdb");
  394. assertTrue(!bogusFile.exists());
  395. try {
  396. Database db = open(bogusFile);
  397. fail("FileNotFoundException should have been thrown");
  398. } catch(FileNotFoundException e) {
  399. }
  400. assertTrue(!bogusFile.exists());
  401. }
  402. public void testReadWithDeletedCols() throws Exception {
  403. Table table = open(new File("test/data/delColTest.mdb")).getTable("Table1");
  404. Map<String, Object> expectedRow0 = new LinkedHashMap<String, Object>();
  405. expectedRow0.put("id", 0);
  406. expectedRow0.put("id2", 2);
  407. expectedRow0.put("data", "foo");
  408. expectedRow0.put("data2", "foo2");
  409. Map<String, Object> expectedRow1 = new LinkedHashMap<String, Object>();
  410. expectedRow1.put("id", 3);
  411. expectedRow1.put("id2", 5);
  412. expectedRow1.put("data", "bar");
  413. expectedRow1.put("data2", "bar2");
  414. int rowNum = 0;
  415. Map<String, Object> row = null;
  416. while ((row = table.getNextRow()) != null) {
  417. if(rowNum == 0) {
  418. assertEquals(expectedRow0, row);
  419. } else if(rowNum == 1) {
  420. assertEquals(expectedRow1, row);
  421. } else if(rowNum >= 2) {
  422. fail("should only have 2 rows");
  423. }
  424. rowNum++;
  425. }
  426. }
  427. public void testCurrency() throws Exception {
  428. Database db = create();
  429. Table table = new TableBuilder("test")
  430. .addColumn(new ColumnBuilder("A", DataType.MONEY).toColumn())
  431. .toTable(db);
  432. table.addRow(new BigDecimal("-2341234.03450"));
  433. table.addRow(37L);
  434. table.addRow("10000.45");
  435. table.reset();
  436. List<Object> foundValues = new ArrayList<Object>();
  437. Map<String, Object> row = null;
  438. while((row = table.getNextRow()) != null) {
  439. foundValues.add(row.get("A"));
  440. }
  441. assertEquals(Arrays.asList(
  442. new BigDecimal("-2341234.0345"),
  443. new BigDecimal("37.0000"),
  444. new BigDecimal("10000.4500")),
  445. foundValues);
  446. try {
  447. table.addRow(new BigDecimal("342523234145343543.3453"));
  448. fail("IOException should have been thrown");
  449. } catch(IOException e) {
  450. // ignored
  451. }
  452. }
  453. public void testGUID() throws Exception
  454. {
  455. Database db = create();
  456. Table table = new TableBuilder("test")
  457. .addColumn(new ColumnBuilder("A", DataType.GUID).toColumn())
  458. .toTable(db);
  459. table.addRow("{32A59F01-AA34-3E29-453F-4523453CD2E6}");
  460. table.addRow("{32a59f01-aa34-3e29-453f-4523453cd2e6}");
  461. table.addRow("{11111111-1111-1111-1111-111111111111}");
  462. table.addRow(" {FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF} ");
  463. table.addRow(UUID.fromString("32a59f01-1234-3e29-4aaf-4523453cd2e6"));
  464. table.reset();
  465. List<Object> foundValues = new ArrayList<Object>();
  466. Map<String, Object> row = null;
  467. while((row = table.getNextRow()) != null) {
  468. foundValues.add(row.get("A"));
  469. }
  470. assertEquals(Arrays.asList(
  471. "{32A59F01-AA34-3E29-453F-4523453CD2E6}",
  472. "{32A59F01-AA34-3E29-453F-4523453CD2E6}",
  473. "{11111111-1111-1111-1111-111111111111}",
  474. "{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}",
  475. "{32A59F01-1234-3E29-4AAF-4523453CD2E6}"),
  476. foundValues);
  477. try {
  478. table.addRow("3245234");
  479. fail("IOException should have been thrown");
  480. } catch(IOException e) {
  481. // ignored
  482. }
  483. }
  484. public void testNumeric() throws Exception
  485. {
  486. Database db = create();
  487. Column col = new ColumnBuilder("A", DataType.NUMERIC)
  488. .setScale(4).setPrecision(8).toColumn();
  489. assertTrue(col.isVariableLength());
  490. Table table = new TableBuilder("test")
  491. .addColumn(col)
  492. .addColumn(new ColumnBuilder("B", DataType.NUMERIC)
  493. .setScale(8).setPrecision(28).toColumn())
  494. .toTable(db);
  495. table.addRow(new BigDecimal("-1234.03450"),
  496. new BigDecimal("23923434453436.36234219"));
  497. table.addRow(37L, 37L);
  498. table.addRow("1000.45", "-3452345321000");
  499. table.reset();
  500. List<Object> foundSmallValues = new ArrayList<Object>();
  501. List<Object> foundBigValues = new ArrayList<Object>();
  502. Map<String, Object> row = null;
  503. while((row = table.getNextRow()) != null) {
  504. foundSmallValues.add(row.get("A"));
  505. foundBigValues.add(row.get("B"));
  506. }
  507. assertEquals(Arrays.asList(
  508. new BigDecimal("-1234.0345"),
  509. new BigDecimal("37.0000"),
  510. new BigDecimal("1000.4500")),
  511. foundSmallValues);
  512. assertEquals(Arrays.asList(
  513. new BigDecimal("23923434453436.36234219"),
  514. new BigDecimal("37.00000000"),
  515. new BigDecimal("-3452345321000.00000000")),
  516. foundBigValues);
  517. try {
  518. table.addRow(new BigDecimal("3245234.234"),
  519. new BigDecimal("3245234.234"));
  520. fail("IOException should have been thrown");
  521. } catch(IOException e) {
  522. // ignored
  523. }
  524. }
  525. public void testFixedNumeric() throws Exception
  526. {
  527. Database db = openCopy(new File("test/data/fixedNumericTest.mdb"));
  528. Table t = db.getTable("test");
  529. boolean first = true;
  530. for(Column col : t.getColumns()) {
  531. if(first) {
  532. assertTrue(col.isVariableLength());
  533. assertEquals(DataType.MEMO, col.getType());
  534. first = false;
  535. } else {
  536. assertFalse(col.isVariableLength());
  537. assertEquals(DataType.NUMERIC, col.getType());
  538. }
  539. }
  540. Map<String, Object> row = t.getNextRow();
  541. assertEquals("some data", row.get("col1"));
  542. assertEquals(new BigDecimal("1"), row.get("col2"));
  543. assertEquals(new BigDecimal("0"), row.get("col3"));
  544. assertEquals(new BigDecimal("0"), row.get("col4"));
  545. assertEquals(new BigDecimal("4"), row.get("col5"));
  546. assertEquals(new BigDecimal("-1"), row.get("col6"));
  547. assertEquals(new BigDecimal("1"), row.get("col7"));
  548. Object[] tmpRow = new Object[]{
  549. "foo", new BigDecimal("1"), new BigDecimal(3), new BigDecimal("13"),
  550. new BigDecimal("-17"), new BigDecimal("0"), new BigDecimal("8734")};
  551. t.addRow(tmpRow);
  552. t.reset();
  553. t.getNextRow();
  554. row = t.getNextRow();
  555. assertEquals(tmpRow[0], row.get("col1"));
  556. assertEquals(tmpRow[1], row.get("col2"));
  557. assertEquals(tmpRow[2], row.get("col3"));
  558. assertEquals(tmpRow[3], row.get("col4"));
  559. assertEquals(tmpRow[4], row.get("col5"));
  560. assertEquals(tmpRow[5], row.get("col6"));
  561. assertEquals(tmpRow[6], row.get("col7"));
  562. db.close();
  563. }
  564. public void testMultiPageTableDef() throws Exception
  565. {
  566. List<Column> columns = open().getTable("Table2").getColumns();
  567. assertEquals(89, columns.size());
  568. }
  569. public void testOverflow() throws Exception
  570. {
  571. Database mdb = open(new File("test/data/overflowTest.mdb"));
  572. Table table = mdb.getTable("Table1");
  573. // 7 rows, 3 and 5 are overflow
  574. table.getNextRow();
  575. table.getNextRow();
  576. Map<String, Object> row = table.getNextRow();
  577. assertEquals(Arrays.<Object>asList(
  578. null, "row3col3", null, null, null, null, null,
  579. "row3col9", null),
  580. new ArrayList<Object>(row.values()));
  581. table.getNextRow();
  582. row = table.getNextRow();
  583. assertEquals(Arrays.<Object>asList(
  584. null, "row5col2", null, null, null, null, null, null,
  585. null),
  586. new ArrayList<Object>(row.values()));
  587. table.reset();
  588. assertRowCount(7, table);
  589. }
  590. public void testLongValueAsMiddleColumn() throws Exception
  591. {
  592. Database db = create();
  593. Table newTable = new TableBuilder("NewTable")
  594. .addColumn(new ColumnBuilder("a").setSQLType(Types.INTEGER).toColumn())
  595. .addColumn(new ColumnBuilder("b").setSQLType(Types.LONGVARCHAR).toColumn())
  596. .addColumn(new ColumnBuilder("c").setSQLType(Types.VARCHAR).toColumn())
  597. .toTable(db);
  598. String lval = createString(2000); // "--2000 chars long text--";
  599. String tval = createString(40); // "--40chars long text--";
  600. newTable.addRow(new Integer(1), lval, tval);
  601. newTable = db.getTable("NewTable");
  602. Map<String, Object> readRow = newTable.getNextRow();
  603. assertEquals(new Integer(1), readRow.get("a"));
  604. assertEquals(lval, readRow.get("b"));
  605. assertEquals(tval, readRow.get("c"));
  606. }
  607. public void testUsageMapPromotion() throws Exception {
  608. Database db = openCopy(new File("test/data/testPromotion.mdb"));
  609. Table t = db.getTable("jobDB1");
  610. String lval = createString(255); // "--255 chars long text--";
  611. for(int i = 0; i < 1000; ++i) {
  612. t.addRow(i, 13, 57, 47.0d, lval, lval, lval, lval, lval, lval);
  613. }
  614. Set<Integer> ids = new HashSet<Integer>();
  615. for(Map<String,Object> row : t) {
  616. ids.add((Integer)row.get("ID"));
  617. }
  618. assertEquals(1000, ids.size());
  619. db.close();
  620. }
  621. public void testLargeTableDef() throws Exception {
  622. final int numColumns = 90;
  623. Database db = create();
  624. List<Column> columns = new ArrayList<Column>();
  625. List<String> colNames = new ArrayList<String>();
  626. for(int i = 0; i < numColumns; ++i) {
  627. String colName = "MyColumnName" + i;
  628. colNames.add(colName);
  629. columns.add(new ColumnBuilder(colName, DataType.TEXT).toColumn());
  630. }
  631. db.createTable("test", columns);
  632. Table t = db.getTable("test");
  633. List<String> row = new ArrayList<String>();
  634. Map<String,Object> expectedRowData = new LinkedHashMap<String, Object>();
  635. for(int i = 0; i < numColumns; ++i) {
  636. String value = "" + i + " some row data";
  637. row.add(value);
  638. expectedRowData.put(colNames.get(i), value);
  639. }
  640. t.addRow(row.toArray());
  641. t.reset();
  642. assertEquals(expectedRowData, t.getNextRow());
  643. db.close();
  644. }
  645. public void testAutoNumber() throws Exception {
  646. Database db = create();
  647. Table table = new TableBuilder("test")
  648. .addColumn(new ColumnBuilder("a", DataType.LONG)
  649. .setAutoNumber(true).toColumn())
  650. .addColumn(new ColumnBuilder("b", DataType.TEXT).toColumn())
  651. .toTable(db);
  652. doTestAutoNumber(table);
  653. db.close();
  654. }
  655. public void testAutoNumberPK() throws Exception {
  656. Database db = openCopy(new File("test/data/test.mdb"));
  657. Table table = db.getTable("Table3");
  658. doTestAutoNumber(table);
  659. db.close();
  660. }
  661. private void doTestAutoNumber(Table table) throws Exception
  662. {
  663. table.addRow(null, "row1");
  664. table.addRow(13, "row2");
  665. table.addRow("flubber", "row3");
  666. table.reset();
  667. table.addRow(Column.AUTO_NUMBER, "row4");
  668. table.addRow(Column.AUTO_NUMBER, "row5");
  669. table.reset();
  670. List<Map<String, Object>> expectedRows =
  671. createExpectedTable(
  672. createExpectedRow(
  673. "a", 1,
  674. "b", "row1"),
  675. createExpectedRow(
  676. "a", 2,
  677. "b", "row2"),
  678. createExpectedRow(
  679. "a", 3,
  680. "b", "row3"),
  681. createExpectedRow(
  682. "a", 4,
  683. "b", "row4"),
  684. createExpectedRow(
  685. "a", 5,
  686. "b", "row5"));
  687. assertTable(expectedRows, table);
  688. }
  689. public void testWriteAndReadDate() throws Exception {
  690. Database db = create();
  691. Table table = new TableBuilder("test")
  692. .addColumn(new ColumnBuilder("name", DataType.TEXT).toColumn())
  693. .addColumn(new ColumnBuilder("date", DataType.SHORT_DATE_TIME)
  694. .toColumn())
  695. .toTable(db);
  696. // since jackcess does not really store millis, shave them off before
  697. // storing the current date/time
  698. long curTimeNoMillis = (System.currentTimeMillis() / 1000L);
  699. curTimeNoMillis *= 1000L;
  700. DateFormat df = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
  701. List<Date> dates =
  702. new ArrayList<Date>(
  703. Arrays.asList(
  704. df.parse("19801231 00:00:00"),
  705. df.parse("19930513 14:43:27"),
  706. null,
  707. df.parse("20210102 02:37:00"),
  708. new Date(curTimeNoMillis)));
  709. Calendar c = Calendar.getInstance();
  710. for(int year = 1801; year < 2050; year +=3) {
  711. for(int month = 0; month <= 12; ++month) {
  712. for(int day = 1; day < 29; day += 3) {
  713. c.clear();
  714. c.set(Calendar.YEAR, year);
  715. c.set(Calendar.MONTH, month);
  716. c.set(Calendar.DAY_OF_MONTH, day);
  717. dates.add(c.getTime());
  718. }
  719. }
  720. }
  721. for(Date d : dates) {
  722. table.addRow("row " + d, d);
  723. }
  724. List<Date> foundDates = new ArrayList<Date>();
  725. for(Map<String,Object> row : table) {
  726. foundDates.add((Date)row.get("date"));
  727. }
  728. assertEquals(dates.size(), foundDates.size());
  729. for(int i = 0; i < dates.size(); ++i) {
  730. Date expected = dates.get(i);
  731. Date found = foundDates.get(i);
  732. if(expected == null) {
  733. assertNull(found);
  734. } else {
  735. // there are some rounding issues due to dates being stored as
  736. // doubles, but it results in a 1 millisecond difference, so i'm not
  737. // going to worry about it
  738. long expTime = expected.getTime();
  739. long foundTime = found.getTime();
  740. try {
  741. assertTrue((expTime == foundTime) ||
  742. (Math.abs(expTime - foundTime) <= 1));
  743. } catch(Error e) {
  744. System.err.println("Expected " + expTime + ", found " + foundTime);
  745. throw e;
  746. }
  747. }
  748. }
  749. }
  750. public void testSystemTable() throws Exception
  751. {
  752. Database db = create();
  753. assertNotNull(db.getSystemTable("MSysAccessObjects"));
  754. assertNotNull(db.getSystemTable("MSysObjects"));
  755. assertNotNull(db.getSystemTable("MSysQueries"));
  756. assertNotNull(db.getSystemTable("MSysACES"));
  757. assertNotNull(db.getSystemTable("MSysRelationships"));
  758. assertNull(db.getSystemTable("MSysBogus"));
  759. db.close();
  760. }
  761. static Object[] createTestRow(String col1Val) {
  762. return new Object[] {col1Val, "R", "McCune", 1234, (byte) 0xad, 555.66d,
  763. 777.88f, (short) 999, new Date()};
  764. }
  765. static Object[] createTestRow() {
  766. return createTestRow("Tim");
  767. }
  768. static void createTestTable(Database db) throws Exception {
  769. new TableBuilder("test")
  770. .addColumn(new ColumnBuilder("A", DataType.TEXT).toColumn())
  771. .addColumn(new ColumnBuilder("B", DataType.TEXT).toColumn())
  772. .addColumn(new ColumnBuilder("C", DataType.TEXT).toColumn())
  773. .addColumn(new ColumnBuilder("D", DataType.LONG).toColumn())
  774. .addColumn(new ColumnBuilder("E", DataType.BYTE).toColumn())
  775. .addColumn(new ColumnBuilder("F", DataType.DOUBLE).toColumn())
  776. .addColumn(new ColumnBuilder("G", DataType.FLOAT).toColumn())
  777. .addColumn(new ColumnBuilder("H", DataType.INT).toColumn())
  778. .addColumn(new ColumnBuilder("I", DataType.SHORT_DATE_TIME).toColumn())
  779. .toTable(db);
  780. }
  781. static String createString(int len) {
  782. StringBuilder builder = new StringBuilder(len);
  783. for(int i = 0; i < len; ++i) {
  784. builder.append((char)('a' + (i % 26)));
  785. }
  786. return builder.toString();
  787. }
  788. static void assertRowCount(int expectedRowCount, Table table)
  789. throws Exception
  790. {
  791. assertEquals(expectedRowCount, countRows(table));
  792. assertEquals(expectedRowCount, table.getRowCount());
  793. }
  794. static int countRows(Table table) throws Exception {
  795. int rtn = 0;
  796. for(Map<String, Object> row : Cursor.createCursor(table)) {
  797. rtn++;
  798. }
  799. return rtn;
  800. }
  801. static void assertTable(List<Map<String, Object>> expectedTable, Table table)
  802. {
  803. assertCursor(expectedTable, Cursor.createCursor(table));
  804. }
  805. static void assertCursor(List<Map<String, Object>> expectedTable,
  806. Cursor cursor)
  807. {
  808. List<Map<String, Object>> foundTable =
  809. new ArrayList<Map<String, Object>>();
  810. for(Map<String, Object> row : cursor) {
  811. foundTable.add(row);
  812. }
  813. assertEquals(expectedTable, foundTable);
  814. }
  815. static Map<String, Object> createExpectedRow(Object... rowElements) {
  816. Map<String, Object> row = new LinkedHashMap<String, Object>();
  817. for(int i = 0; i < rowElements.length; i += 2) {
  818. row.put((String)rowElements[i],
  819. rowElements[i + 1]);
  820. }
  821. return row;
  822. }
  823. @SuppressWarnings("unchecked")
  824. static List<Map<String, Object>> createExpectedTable(Map... rows) {
  825. return Arrays.<Map<String, Object>>asList(rows);
  826. }
  827. static void dumpDatabase(Database mdb) throws Exception {
  828. dumpDatabase(mdb, new PrintWriter(System.out, true));
  829. }
  830. static void dumpTable(Table table) throws Exception {
  831. dumpTable(table, new PrintWriter(System.out, true));
  832. }
  833. static void dumpDatabase(Database mdb, PrintWriter writer) throws Exception {
  834. writer.println("DATABASE:");
  835. for(Table table : mdb) {
  836. dumpTable(table, writer);
  837. }
  838. }
  839. static void dumpTable(Table table, PrintWriter writer) throws Exception {
  840. // make sure all indexes are read
  841. for(Index index : table.getIndexes()) {
  842. index.initialize();
  843. }
  844. writer.println("TABLE: " + table.getName());
  845. List<String> colNames = new ArrayList<String>();
  846. for(Column col : table.getColumns()) {
  847. colNames.add(col.getName());
  848. }
  849. writer.println("COLUMNS: " + colNames);
  850. for(Map<String, Object> row : Cursor.createCursor(table)) {
  851. // make byte[] printable
  852. for(Map.Entry<String, Object> entry : row.entrySet()) {
  853. Object v = entry.getValue();
  854. if(v instanceof byte[]) {
  855. byte[] bv = (byte[])v;
  856. entry.setValue(ByteUtil.toHexString(ByteBuffer.wrap(bv), bv.length));
  857. }
  858. }
  859. writer.println(row);
  860. }
  861. }
  862. static void copyFile(File srcFile, File dstFile)
  863. throws IOException
  864. {
  865. // FIXME should really be using commons io FileUtils here, but don't want
  866. // to add dep for one simple test method
  867. byte[] buf = new byte[1024];
  868. OutputStream ostream = new FileOutputStream(dstFile);
  869. InputStream istream = new FileInputStream(srcFile);
  870. try {
  871. int numBytes = 0;
  872. while((numBytes = istream.read(buf)) >= 0) {
  873. ostream.write(buf, 0, numBytes);
  874. }
  875. } finally {
  876. ostream.close();
  877. }
  878. }
  879. static File createTempFile(boolean keep) throws Exception {
  880. File tmp = File.createTempFile("databaseTest", ".mdb");
  881. if(keep) {
  882. System.out.println("Created " + tmp);
  883. } else {
  884. tmp.deleteOnExit();
  885. }
  886. return tmp;
  887. }
  888. static byte[] toByteArray(File file)
  889. throws IOException
  890. {
  891. // FIXME should really be using commons io IOUtils here, but don't want
  892. // to add dep for one simple test method
  893. FileInputStream istream = new FileInputStream(file);
  894. try {
  895. byte[] bytes = new byte[(int)file.length()];
  896. istream.read(bytes);
  897. return bytes;
  898. } finally {
  899. istream.close();
  900. }
  901. }
  902. }