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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032
  1. /*
  2. Copyright (c) 2007 Health Market Science, Inc.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package com.healthmarketscience.jackcess;
  14. import java.io.File;
  15. import java.io.FileNotFoundException;
  16. import java.io.IOException;
  17. import java.math.BigDecimal;
  18. import java.text.DateFormat;
  19. import java.text.SimpleDateFormat;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.Calendar;
  23. import java.util.Date;
  24. import java.util.HashSet;
  25. import java.util.LinkedHashMap;
  26. import java.util.List;
  27. import java.util.Map;
  28. import java.util.Set;
  29. import java.util.TimeZone;
  30. import java.util.TreeSet;
  31. import java.util.UUID;
  32. import static com.healthmarketscience.jackcess.Database.*;
  33. import com.healthmarketscience.jackcess.impl.ColumnImpl;
  34. import com.healthmarketscience.jackcess.impl.DatabaseImpl;
  35. import static com.healthmarketscience.jackcess.impl.JetFormatTest.*;
  36. import com.healthmarketscience.jackcess.impl.RowIdImpl;
  37. import com.healthmarketscience.jackcess.impl.RowImpl;
  38. import com.healthmarketscience.jackcess.impl.TableImpl;
  39. import com.healthmarketscience.jackcess.util.LinkResolver;
  40. import com.healthmarketscience.jackcess.util.RowFilterTest;
  41. import junit.framework.TestCase;
  42. import static com.healthmarketscience.jackcess.TestUtil.*;
  43. /**
  44. * @author Tim McCune
  45. */
  46. public class DatabaseTest extends TestCase
  47. {
  48. public DatabaseTest(String name) throws Exception {
  49. super(name);
  50. }
  51. public void testInvalidTableDefs() throws Exception {
  52. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  53. Database db = create(fileFormat);
  54. try {
  55. new TableBuilder("test").toTable(db);
  56. fail("created table with no columns?");
  57. } catch(IllegalArgumentException e) {
  58. // success
  59. }
  60. try {
  61. new TableBuilder("test")
  62. .addColumn(new ColumnBuilder("A", DataType.TEXT))
  63. .addColumn(new ColumnBuilder("a", DataType.MEMO))
  64. .toTable(db);
  65. fail("created table with duplicate column names?");
  66. } catch(IllegalArgumentException e) {
  67. // success
  68. }
  69. try {
  70. new TableBuilder("test")
  71. .addColumn(new ColumnBuilder("A", DataType.TEXT)
  72. .setLengthInUnits(352))
  73. .toTable(db);
  74. fail("created table with invalid column length?");
  75. } catch(IllegalArgumentException e) {
  76. // success
  77. }
  78. try {
  79. new TableBuilder("test")
  80. .addColumn(new ColumnBuilder("A_" + createString(70), DataType.TEXT))
  81. .toTable(db);
  82. fail("created table with too long column name?");
  83. } catch(IllegalArgumentException e) {
  84. // success
  85. }
  86. new TableBuilder("test")
  87. .addColumn(new ColumnBuilder("A", DataType.TEXT))
  88. .toTable(db);
  89. try {
  90. new TableBuilder("Test")
  91. .addColumn(new ColumnBuilder("A", DataType.TEXT))
  92. .toTable(db);
  93. fail("create duplicate tables?");
  94. } catch(IllegalArgumentException e) {
  95. // success
  96. }
  97. db.close();
  98. }
  99. }
  100. public void testReadDeletedRows() throws Exception {
  101. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.DEL, true)) {
  102. Table table = open(testDB).getTable("Table");
  103. int rows = 0;
  104. while (table.getNextRow() != null) {
  105. rows++;
  106. }
  107. assertEquals(2, rows);
  108. table.getDatabase().close();
  109. }
  110. }
  111. public void testGetColumns() throws Exception {
  112. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  113. List<? extends Column> columns = open(testDB).getTable("Table1").getColumns();
  114. assertEquals(9, columns.size());
  115. checkColumn(columns, 0, "A", DataType.TEXT);
  116. checkColumn(columns, 1, "B", DataType.TEXT);
  117. checkColumn(columns, 2, "C", DataType.BYTE);
  118. checkColumn(columns, 3, "D", DataType.INT);
  119. checkColumn(columns, 4, "E", DataType.LONG);
  120. checkColumn(columns, 5, "F", DataType.DOUBLE);
  121. checkColumn(columns, 6, "G", DataType.SHORT_DATE_TIME);
  122. checkColumn(columns, 7, "H", DataType.MONEY);
  123. checkColumn(columns, 8, "I", DataType.BOOLEAN);
  124. }
  125. }
  126. private static void checkColumn(
  127. List<? extends Column> columns, int columnNumber, String name,
  128. DataType dataType)
  129. throws Exception
  130. {
  131. Column column = columns.get(columnNumber);
  132. assertEquals(name, column.getName());
  133. assertEquals(dataType, column.getType());
  134. }
  135. public void testGetNextRow() throws Exception {
  136. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  137. final Database db = open(testDB);
  138. assertEquals(4, db.getTableNames().size());
  139. final Table table = db.getTable("Table1");
  140. Row row1 = table.getNextRow();
  141. Row row2 = table.getNextRow();
  142. if(!"abcdefg".equals(row1.get("A"))) {
  143. Row tmpRow = row1;
  144. row1 = row2;
  145. row2 = tmpRow;
  146. }
  147. checkTestDBTable1RowABCDEFG(testDB, table, row1);
  148. checkTestDBTable1RowA(testDB, table, row2);
  149. db.close();
  150. }
  151. }
  152. public void testCreate() throws Exception {
  153. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  154. Database db = create(fileFormat);
  155. assertEquals(0, db.getTableNames().size());
  156. db.close();
  157. }
  158. }
  159. public void testDeleteCurrentRow() throws Exception {
  160. // make sure correct row is deleted
  161. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  162. Database db = createMem(fileFormat);
  163. createTestTable(db);
  164. Map<String,Object> row1 = createTestRowMap("Tim1");
  165. Map<String,Object> row2 = createTestRowMap("Tim2");
  166. Map<String,Object> row3 = createTestRowMap("Tim3");
  167. Table table = db.getTable("Test");
  168. @SuppressWarnings("unchecked")
  169. List<Map<String,Object>> rows = Arrays.asList(row1, row2, row3);
  170. table.addRowsFromMaps(rows);
  171. assertRowCount(3, table);
  172. table.reset();
  173. table.getNextRow();
  174. table.getNextRow();
  175. table.getDefaultCursor().deleteCurrentRow();
  176. table.reset();
  177. Map<String, Object> outRow = table.getNextRow();
  178. assertEquals("Tim1", outRow.get("A"));
  179. outRow = table.getNextRow();
  180. assertEquals("Tim3", outRow.get("A"));
  181. assertRowCount(2, table);
  182. db.close();
  183. // test multi row delete/add
  184. db = createMem(fileFormat);
  185. createTestTable(db);
  186. Object[] row = createTestRow();
  187. table = db.getTable("Test");
  188. for (int i = 0; i < 10; i++) {
  189. row[3] = i;
  190. table.addRow(row);
  191. }
  192. row[3] = 1974;
  193. assertRowCount(10, table);
  194. table.reset();
  195. table.getNextRow();
  196. table.getDefaultCursor().deleteCurrentRow();
  197. assertRowCount(9, table);
  198. table.reset();
  199. table.getNextRow();
  200. table.getDefaultCursor().deleteCurrentRow();
  201. assertRowCount(8, table);
  202. table.reset();
  203. for (int i = 0; i < 8; i++) {
  204. table.getNextRow();
  205. }
  206. table.getDefaultCursor().deleteCurrentRow();
  207. assertRowCount(7, table);
  208. table.addRow(row);
  209. assertRowCount(8, table);
  210. table.reset();
  211. for (int i = 0; i < 3; i++) {
  212. table.getNextRow();
  213. }
  214. table.getDefaultCursor().deleteCurrentRow();
  215. assertRowCount(7, table);
  216. table.reset();
  217. assertEquals(2, table.getNextRow().get("D"));
  218. db.close();
  219. }
  220. }
  221. public void testDeleteRow() throws Exception {
  222. // make sure correct row is deleted
  223. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  224. Database db = createMem(fileFormat);
  225. createTestTable(db);
  226. Table table = db.getTable("Test");
  227. for(int i = 0; i < 10; ++i) {
  228. table.addRowFromMap(createTestRowMap("Tim" + i));
  229. }
  230. assertRowCount(10, table);
  231. table.reset();
  232. List<Row> rows = RowFilterTest.toList(table);
  233. Row r1 = rows.remove(7);
  234. Row r2 = rows.remove(3);
  235. assertEquals(8, rows.size());
  236. assertSame(r2, table.deleteRow(r2));
  237. assertSame(r1, table.deleteRow(r1));
  238. assertTable(rows, table);
  239. table.deleteRow(r2);
  240. table.deleteRow(r1);
  241. assertTable(rows, table);
  242. }
  243. }
  244. public void testMissingFile() throws Exception {
  245. File bogusFile = new File("fooby-dooby.mdb");
  246. assertTrue(!bogusFile.exists());
  247. try {
  248. new DatabaseBuilder(bogusFile).setReadOnly(true).
  249. setAutoSync(getTestAutoSync()).open();
  250. fail("FileNotFoundException should have been thrown");
  251. } catch(FileNotFoundException e) {
  252. }
  253. assertTrue(!bogusFile.exists());
  254. }
  255. public void testReadWithDeletedCols() throws Exception {
  256. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.DEL_COL, true)) {
  257. Table table = open(testDB).getTable("Table1");
  258. Map<String, Object> expectedRow0 = new LinkedHashMap<String, Object>();
  259. expectedRow0.put("id", 0);
  260. expectedRow0.put("id2", 2);
  261. expectedRow0.put("data", "foo");
  262. expectedRow0.put("data2", "foo2");
  263. Map<String, Object> expectedRow1 = new LinkedHashMap<String, Object>();
  264. expectedRow1.put("id", 3);
  265. expectedRow1.put("id2", 5);
  266. expectedRow1.put("data", "bar");
  267. expectedRow1.put("data2", "bar2");
  268. int rowNum = 0;
  269. Map<String, Object> row = null;
  270. while ((row = table.getNextRow()) != null) {
  271. if(rowNum == 0) {
  272. assertEquals(expectedRow0, row);
  273. } else if(rowNum == 1) {
  274. assertEquals(expectedRow1, row);
  275. } else if(rowNum >= 2) {
  276. fail("should only have 2 rows");
  277. }
  278. rowNum++;
  279. }
  280. table.getDatabase().close();
  281. }
  282. }
  283. public void testCurrency() throws Exception {
  284. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  285. Database db = create(fileFormat);
  286. Table table = new TableBuilder("test")
  287. .addColumn(new ColumnBuilder("A", DataType.MONEY))
  288. .toTable(db);
  289. table.addRow(new BigDecimal("-2341234.03450"));
  290. table.addRow(37L);
  291. table.addRow("10000.45");
  292. table.reset();
  293. List<Object> foundValues = new ArrayList<Object>();
  294. Map<String, Object> row = null;
  295. while((row = table.getNextRow()) != null) {
  296. foundValues.add(row.get("A"));
  297. }
  298. assertEquals(Arrays.asList(
  299. new BigDecimal("-2341234.0345"),
  300. new BigDecimal("37.0000"),
  301. new BigDecimal("10000.4500")),
  302. foundValues);
  303. try {
  304. table.addRow(new BigDecimal("342523234145343543.3453"));
  305. fail("IOException should have been thrown");
  306. } catch(IOException e) {
  307. // ignored
  308. }
  309. db.close();
  310. }
  311. }
  312. public void testGUID() throws Exception
  313. {
  314. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  315. Database db = create(fileFormat);
  316. Table table = new TableBuilder("test")
  317. .addColumn(new ColumnBuilder("A", DataType.GUID))
  318. .toTable(db);
  319. table.addRow("{32A59F01-AA34-3E29-453F-4523453CD2E6}");
  320. table.addRow("{32a59f01-aa34-3e29-453f-4523453cd2e6}");
  321. table.addRow("{11111111-1111-1111-1111-111111111111}");
  322. table.addRow(" {FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF} ");
  323. table.addRow(UUID.fromString("32a59f01-1234-3e29-4aaf-4523453cd2e6"));
  324. table.reset();
  325. List<Object> foundValues = new ArrayList<Object>();
  326. Map<String, Object> row = null;
  327. while((row = table.getNextRow()) != null) {
  328. foundValues.add(row.get("A"));
  329. }
  330. assertEquals(Arrays.asList(
  331. "{32A59F01-AA34-3E29-453F-4523453CD2E6}",
  332. "{32A59F01-AA34-3E29-453F-4523453CD2E6}",
  333. "{11111111-1111-1111-1111-111111111111}",
  334. "{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}",
  335. "{32A59F01-1234-3E29-4AAF-4523453CD2E6}"),
  336. foundValues);
  337. try {
  338. table.addRow("3245234");
  339. fail("IOException should have been thrown");
  340. } catch(IOException e) {
  341. // ignored
  342. }
  343. db.close();
  344. }
  345. }
  346. public void testNumeric() throws Exception
  347. {
  348. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  349. Database db = create(fileFormat);
  350. ColumnBuilder col = new ColumnBuilder("A", DataType.NUMERIC)
  351. .setScale(4).setPrecision(8).toColumn();
  352. assertTrue(col.getType().isVariableLength());
  353. Table table = new TableBuilder("test")
  354. .addColumn(col)
  355. .addColumn(new ColumnBuilder("B", DataType.NUMERIC)
  356. .setScale(8).setPrecision(28))
  357. .toTable(db);
  358. table.addRow(new BigDecimal("-1234.03450"),
  359. new BigDecimal("23923434453436.36234219"));
  360. table.addRow(37L, 37L);
  361. table.addRow("1000.45", "-3452345321000");
  362. table.reset();
  363. List<Object> foundSmallValues = new ArrayList<Object>();
  364. List<Object> foundBigValues = new ArrayList<Object>();
  365. Map<String, Object> row = null;
  366. while((row = table.getNextRow()) != null) {
  367. foundSmallValues.add(row.get("A"));
  368. foundBigValues.add(row.get("B"));
  369. }
  370. assertEquals(Arrays.asList(
  371. new BigDecimal("-1234.0345"),
  372. new BigDecimal("37.0000"),
  373. new BigDecimal("1000.4500")),
  374. foundSmallValues);
  375. assertEquals(Arrays.asList(
  376. new BigDecimal("23923434453436.36234219"),
  377. new BigDecimal("37.00000000"),
  378. new BigDecimal("-3452345321000.00000000")),
  379. foundBigValues);
  380. try {
  381. table.addRow(new BigDecimal("3245234.234"),
  382. new BigDecimal("3245234.234"));
  383. fail("IOException should have been thrown");
  384. } catch(IOException e) {
  385. // ignored
  386. }
  387. db.close();
  388. }
  389. }
  390. public void testFixedNumeric() throws Exception
  391. {
  392. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.FIXED_NUMERIC)) {
  393. Database db = openCopy(testDB);
  394. Table t = db.getTable("test");
  395. boolean first = true;
  396. for(Column col : t.getColumns()) {
  397. if(first) {
  398. assertTrue(col.isVariableLength());
  399. assertEquals(DataType.MEMO, col.getType());
  400. first = false;
  401. } else {
  402. assertFalse(col.isVariableLength());
  403. assertEquals(DataType.NUMERIC, col.getType());
  404. }
  405. }
  406. Map<String, Object> row = t.getNextRow();
  407. assertEquals("some data", row.get("col1"));
  408. assertEquals(new BigDecimal("1"), row.get("col2"));
  409. assertEquals(new BigDecimal("0"), row.get("col3"));
  410. assertEquals(new BigDecimal("0"), row.get("col4"));
  411. assertEquals(new BigDecimal("4"), row.get("col5"));
  412. assertEquals(new BigDecimal("-1"), row.get("col6"));
  413. assertEquals(new BigDecimal("1"), row.get("col7"));
  414. Object[] tmpRow = new Object[]{
  415. "foo", new BigDecimal("1"), new BigDecimal(3), new BigDecimal("13"),
  416. new BigDecimal("-17"), new BigDecimal("0"), new BigDecimal("8734")};
  417. t.addRow(tmpRow);
  418. t.reset();
  419. t.getNextRow();
  420. row = t.getNextRow();
  421. assertEquals(tmpRow[0], row.get("col1"));
  422. assertEquals(tmpRow[1], row.get("col2"));
  423. assertEquals(tmpRow[2], row.get("col3"));
  424. assertEquals(tmpRow[3], row.get("col4"));
  425. assertEquals(tmpRow[4], row.get("col5"));
  426. assertEquals(tmpRow[5], row.get("col6"));
  427. assertEquals(tmpRow[6], row.get("col7"));
  428. db.close();
  429. }
  430. }
  431. public void testMultiPageTableDef() throws Exception
  432. {
  433. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  434. List<? extends Column> columns = open(testDB).getTable("Table2").getColumns();
  435. assertEquals(89, columns.size());
  436. }
  437. }
  438. public void testOverflow() throws Exception
  439. {
  440. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.OVERFLOW, true)) {
  441. Database mdb = open(testDB);
  442. Table table = mdb.getTable("Table1");
  443. // 7 rows, 3 and 5 are overflow
  444. table.getNextRow();
  445. table.getNextRow();
  446. Map<String, Object> row = table.getNextRow();
  447. assertEquals(Arrays.<Object>asList(
  448. null, "row3col3", null, null, null, null, null,
  449. "row3col9", null),
  450. new ArrayList<Object>(row.values()));
  451. table.getNextRow();
  452. row = table.getNextRow();
  453. assertEquals(Arrays.<Object>asList(
  454. null, "row5col2", null, null, null, null, null, null,
  455. null),
  456. new ArrayList<Object>(row.values()));
  457. table.reset();
  458. assertRowCount(7, table);
  459. mdb.close();
  460. }
  461. }
  462. public void testUsageMapPromotion() throws Exception {
  463. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.PROMOTION)) {
  464. Database db = openMem(testDB);
  465. Table t = db.getTable("jobDB1");
  466. assertTrue(((TableImpl)t).getOwnedPagesCursor().getUsageMap().toString()
  467. .startsWith("InlineHandler"));
  468. String lval = createNonAsciiString(255); // "--255 chars long text--";
  469. ((DatabaseImpl)db).getPageChannel().startWrite();
  470. try {
  471. for(int i = 0; i < 1000; ++i) {
  472. t.addRow(i, 13, 57, lval, lval, lval, lval, lval, lval, 47.0d);
  473. }
  474. } finally {
  475. ((DatabaseImpl)db).getPageChannel().finishWrite();
  476. }
  477. Set<Integer> ids = new HashSet<Integer>();
  478. for(Row row : t) {
  479. ids.add(row.getInt("ID"));
  480. }
  481. assertEquals(1000, ids.size());
  482. assertTrue(((TableImpl)t).getOwnedPagesCursor().getUsageMap().toString()
  483. .startsWith("ReferenceHandler"));
  484. db.close();
  485. }
  486. }
  487. public void testLargeTableDef() throws Exception {
  488. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  489. Database db = create(fileFormat);
  490. final int numColumns = 90;
  491. List<ColumnBuilder> columns = new ArrayList<ColumnBuilder>();
  492. List<String> colNames = new ArrayList<String>();
  493. for(int i = 0; i < numColumns; ++i) {
  494. String colName = "MyColumnName" + i;
  495. colNames.add(colName);
  496. columns.add(new ColumnBuilder(colName, DataType.TEXT).toColumn());
  497. }
  498. Table t = new TableBuilder("test")
  499. .addColumns(columns)
  500. .toTable(db);
  501. List<String> row = new ArrayList<String>();
  502. Map<String,Object> expectedRowData = new LinkedHashMap<String, Object>();
  503. for(int i = 0; i < numColumns; ++i) {
  504. String value = "" + i + " some row data";
  505. row.add(value);
  506. expectedRowData.put(colNames.get(i), value);
  507. }
  508. t.addRow(row.toArray());
  509. t.reset();
  510. assertEquals(expectedRowData, t.getNextRow());
  511. db.close();
  512. }
  513. }
  514. public void testWriteAndReadDate() throws Exception {
  515. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  516. Database db = createMem(fileFormat);
  517. Table table = new TableBuilder("test")
  518. .addColumn(new ColumnBuilder("name", DataType.TEXT))
  519. .addColumn(new ColumnBuilder("date", DataType.SHORT_DATE_TIME))
  520. .toTable(db);
  521. // since jackcess does not really store millis, shave them off before
  522. // storing the current date/time
  523. long curTimeNoMillis = (System.currentTimeMillis() / 1000L);
  524. curTimeNoMillis *= 1000L;
  525. DateFormat df = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
  526. List<Date> dates =
  527. new ArrayList<Date>(
  528. Arrays.asList(
  529. df.parse("19801231 00:00:00"),
  530. df.parse("19930513 14:43:27"),
  531. null,
  532. df.parse("20210102 02:37:00"),
  533. new Date(curTimeNoMillis)));
  534. Calendar c = Calendar.getInstance();
  535. for(int year = 1801; year < 2050; year +=3) {
  536. for(int month = 0; month <= 12; ++month) {
  537. for(int day = 1; day < 29; day += 3) {
  538. c.clear();
  539. c.set(Calendar.YEAR, year);
  540. c.set(Calendar.MONTH, month);
  541. c.set(Calendar.DAY_OF_MONTH, day);
  542. dates.add(c.getTime());
  543. }
  544. }
  545. }
  546. ((DatabaseImpl)db).getPageChannel().startWrite();
  547. try {
  548. for(Date d : dates) {
  549. table.addRow("row " + d, d);
  550. }
  551. } finally {
  552. ((DatabaseImpl)db).getPageChannel().finishWrite();
  553. }
  554. List<Date> foundDates = new ArrayList<Date>();
  555. for(Row row : table) {
  556. foundDates.add(row.getDate("date"));
  557. }
  558. assertEquals(dates.size(), foundDates.size());
  559. for(int i = 0; i < dates.size(); ++i) {
  560. Date expected = dates.get(i);
  561. Date found = foundDates.get(i);
  562. assertSameDate(expected, found);
  563. }
  564. db.close();
  565. }
  566. }
  567. public void testAncientDates() throws Exception
  568. {
  569. TimeZone tz = TimeZone.getTimeZone("America/New_York");
  570. SimpleDateFormat sdf = DatabaseBuilder.createDateFormat("yyyy-MM-dd");
  571. sdf.getCalendar().setTimeZone(tz);
  572. List<String> dates = Arrays.asList("1582-10-15", "1582-10-14",
  573. "1492-01-10", "1392-01-10");
  574. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  575. Database db = createMem(fileFormat);
  576. db.setTimeZone(tz);
  577. Table table = new TableBuilder("test")
  578. .addColumn(new ColumnBuilder("name", DataType.TEXT))
  579. .addColumn(new ColumnBuilder("date", DataType.SHORT_DATE_TIME))
  580. .toTable(db);
  581. for(String dateStr : dates) {
  582. Date d = sdf.parse(dateStr);
  583. table.addRow("row " + dateStr, d);
  584. }
  585. List<String> foundDates = new ArrayList<String>();
  586. for(Row row : table) {
  587. foundDates.add(sdf.format(row.getDate("date")));
  588. }
  589. assertEquals(dates, foundDates);
  590. db.close();
  591. }
  592. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.OLD_DATES)) {
  593. Database db = openCopy(testDB);
  594. Table t = db.getTable("Table1");
  595. List<String> foundDates = new ArrayList<String>();
  596. for(Row row : t) {
  597. foundDates.add(sdf.format(row.getDate("DateField")));
  598. }
  599. assertEquals(dates, foundDates);
  600. db.close();
  601. }
  602. }
  603. public void testSystemTable() throws Exception
  604. {
  605. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  606. Database db = create(fileFormat);
  607. Set<String> sysTables = new TreeSet<String>(
  608. String.CASE_INSENSITIVE_ORDER);
  609. sysTables.addAll(
  610. Arrays.asList("MSysObjects", "MSysQueries", "MSysACES",
  611. "MSysRelationships"));
  612. if (fileFormat.ordinal() < FileFormat.V2003.ordinal()) {
  613. assertNotNull("file format: " + fileFormat, db.getSystemTable("MSysAccessObjects"));
  614. sysTables.add("MSysAccessObjects");
  615. } else {
  616. // v2003+ template files have no "MSysAccessObjects" table
  617. assertNull("file format: " + fileFormat, db.getSystemTable("MSysAccessObjects"));
  618. sysTables.addAll(
  619. Arrays.asList("MSysNavPaneGroupCategories",
  620. "MSysNavPaneGroups", "MSysNavPaneGroupToObjects",
  621. "MSysNavPaneObjectIDs", "MSysAccessStorage"));
  622. if(fileFormat.ordinal() >= FileFormat.V2007.ordinal()) {
  623. sysTables.addAll(
  624. Arrays.asList(
  625. "MSysComplexColumns", "MSysComplexType_Attachment",
  626. "MSysComplexType_Decimal", "MSysComplexType_GUID",
  627. "MSysComplexType_IEEEDouble", "MSysComplexType_IEEESingle",
  628. "MSysComplexType_Long", "MSysComplexType_Short",
  629. "MSysComplexType_Text", "MSysComplexType_UnsignedByte"));
  630. }
  631. if(fileFormat.ordinal() >= FileFormat.V2010.ordinal()) {
  632. sysTables.add("f_12D7448B56564D8AAE333BCC9B3718E5_Data");
  633. sysTables.add("MSysResources");
  634. }
  635. }
  636. assertEquals(sysTables, db.getSystemTableNames());
  637. assertNotNull(db.getSystemTable("MSysObjects"));
  638. assertNotNull(db.getSystemTable("MSysQueries"));
  639. assertNotNull(db.getSystemTable("MSysACES"));
  640. assertNotNull(db.getSystemTable("MSysRelationships"));
  641. assertNull(db.getSystemTable("MSysBogus"));
  642. TableMetaData tmd = db.getTableMetaData("MSysObjects");
  643. assertEquals("MSysObjects", tmd.getName());
  644. assertFalse(tmd.isLinked());
  645. assertTrue(tmd.isSystem());
  646. db.close();
  647. }
  648. }
  649. public void testFixedText() throws Exception
  650. {
  651. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.FIXED_TEXT)) {
  652. Database db = openCopy(testDB);
  653. Table t = db.getTable("users");
  654. Column c = t.getColumn("c_flag_");
  655. assertEquals(DataType.TEXT, c.getType());
  656. assertEquals(false, c.isVariableLength());
  657. assertEquals(2, c.getLength());
  658. Map<String,Object> row = t.getNextRow();
  659. assertEquals("N", row.get("c_flag_"));
  660. t.addRow(3, "testFixedText", "boo", "foo", "bob", 3, 5, 9, "Y",
  661. new Date());
  662. t.getNextRow();
  663. row = t.getNextRow();
  664. assertEquals("testFixedText", row.get("c_user_login"));
  665. assertEquals("Y", row.get("c_flag_"));
  666. db.close();
  667. }
  668. }
  669. public void testDbSortOrder() throws Exception {
  670. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  671. Database db = open(testDB);
  672. assertEquals(((DatabaseImpl)db).getFormat().DEFAULT_SORT_ORDER,
  673. ((DatabaseImpl)db).getDefaultSortOrder());
  674. db.close();
  675. }
  676. }
  677. public void testUnsupportedColumns() throws Exception {
  678. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.UNSUPPORTED)) {
  679. Database db = open(testDB);
  680. Table t = db.getTable("Test");
  681. Column varCol = t.getColumn("UnknownVar");
  682. assertEquals(DataType.UNSUPPORTED_VARLEN, varCol.getType());
  683. Column fixCol = t.getColumn("UnknownFix");
  684. assertEquals(DataType.UNSUPPORTED_FIXEDLEN, fixCol.getType());
  685. List<String> varVals = Arrays.asList(
  686. "RawData[(10) FF FE 73 6F 6D 65 64 61 74 61]",
  687. "RawData[(12) FF FE 6F 74 68 65 72 20 64 61 74 61]",
  688. null);
  689. List<String> fixVals = Arrays.asList("RawData[(4) 37 00 00 00]",
  690. "RawData[(4) F3 FF FF FF]",
  691. "RawData[(4) 02 00 00 00]");
  692. int idx = 0;
  693. for(Map<String,Object> row : t) {
  694. checkRawValue(varVals.get(idx), varCol.getRowValue(row));
  695. checkRawValue(fixVals.get(idx), fixCol.getRowValue(row));
  696. ++idx;
  697. }
  698. db.close();
  699. }
  700. }
  701. public void testLinkedTables() throws Exception {
  702. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.LINKED)) {
  703. Database db = openCopy(testDB);
  704. try {
  705. db.getTable("Table2");
  706. fail("FileNotFoundException should have been thrown");
  707. } catch(FileNotFoundException e) {
  708. // success
  709. }
  710. TableMetaData tmd = db.getTableMetaData("Table2");
  711. assertEquals("Table2", tmd.getName());
  712. assertTrue(tmd.isLinked());
  713. assertFalse(tmd.isSystem());
  714. assertEquals("Table1", tmd.getLinkedTableName());
  715. assertEquals("Z:\\jackcess_test\\linkeeTest.accdb", tmd.getLinkedDbName());
  716. tmd = db.getTableMetaData("FooTable");
  717. assertNull(tmd);
  718. assertTrue(db.getLinkedDatabases().isEmpty());
  719. final String linkeeDbName = "Z:\\jackcess_test\\linkeeTest.accdb";
  720. final File linkeeFile = new File("src/test/data/linkeeTest.accdb");
  721. db.setLinkResolver(new LinkResolver() {
  722. public Database resolveLinkedDatabase(Database linkerdb, String dbName)
  723. throws IOException {
  724. assertEquals(linkeeDbName, dbName);
  725. return DatabaseBuilder.open(linkeeFile);
  726. }
  727. });
  728. Table t2 = db.getTable("Table2");
  729. assertEquals(1, db.getLinkedDatabases().size());
  730. Database linkeeDb = db.getLinkedDatabases().get(linkeeDbName);
  731. assertNotNull(linkeeDb);
  732. assertEquals(linkeeFile, linkeeDb.getFile());
  733. List<? extends Map<String, Object>> expectedRows =
  734. createExpectedTable(
  735. createExpectedRow(
  736. "ID", 1,
  737. "Field1", "bar"));
  738. assertTable(expectedRows, t2);
  739. db.createLinkedTable("FooTable", linkeeDbName, "Table2");
  740. tmd = db.getTableMetaData("FooTable");
  741. assertEquals("FooTable", tmd.getName());
  742. assertTrue(tmd.isLinked());
  743. assertFalse(tmd.isSystem());
  744. assertEquals("Table2", tmd.getLinkedTableName());
  745. assertEquals("Z:\\jackcess_test\\linkeeTest.accdb", tmd.getLinkedDbName());
  746. Table t3 = db.getTable("FooTable");
  747. assertEquals(1, db.getLinkedDatabases().size());
  748. expectedRows =
  749. createExpectedTable(
  750. createExpectedRow(
  751. "ID", 1,
  752. "Field1", "buzz"));
  753. assertTable(expectedRows, t3);
  754. tmd = db.getTableMetaData("Table1");
  755. assertEquals("Table1", tmd.getName());
  756. assertFalse(tmd.isLinked());
  757. assertFalse(tmd.isSystem());
  758. assertNull(tmd.getLinkedTableName());
  759. assertNull(tmd.getLinkedDbName());
  760. Table t1 = tmd.open(db);
  761. assertFalse(db.isLinkedTable(null));
  762. assertTrue(db.isLinkedTable(t2));
  763. assertTrue(db.isLinkedTable(t3));
  764. assertFalse(db.isLinkedTable(t1));
  765. List<Table> tables = getTables(db.newIterable());
  766. assertEquals(3, tables.size());
  767. assertTrue(tables.contains(t1));
  768. assertTrue(tables.contains(t2));
  769. assertTrue(tables.contains(t3));
  770. assertFalse(tables.contains(((DatabaseImpl)db).getSystemCatalog()));
  771. tables = getTables(db.newIterable().setIncludeNormalTables(false));
  772. assertEquals(2, tables.size());
  773. assertFalse(tables.contains(t1));
  774. assertTrue(tables.contains(t2));
  775. assertTrue(tables.contains(t3));
  776. assertFalse(tables.contains(((DatabaseImpl)db).getSystemCatalog()));
  777. tables = getTables(db.newIterable().withLocalUserTablesOnly());
  778. assertEquals(1, tables.size());
  779. assertTrue(tables.contains(t1));
  780. assertFalse(tables.contains(t2));
  781. assertFalse(tables.contains(t3));
  782. assertFalse(tables.contains(((DatabaseImpl)db).getSystemCatalog()));
  783. tables = getTables(db.newIterable().withSystemTablesOnly());
  784. assertTrue(tables.size() > 5);
  785. assertFalse(tables.contains(t1));
  786. assertFalse(tables.contains(t2));
  787. assertFalse(tables.contains(t3));
  788. assertTrue(tables.contains(((DatabaseImpl)db).getSystemCatalog()));
  789. db.close();
  790. }
  791. }
  792. private static List<Table> getTables(Iterable<Table> tableIter)
  793. {
  794. List<Table> tableList = new ArrayList<Table>();
  795. for(Table t : tableIter) {
  796. tableList.add(t);
  797. }
  798. return tableList;
  799. }
  800. public void testTimeZone() throws Exception
  801. {
  802. TimeZone tz = TimeZone.getTimeZone("America/New_York");
  803. doTestTimeZone(tz);
  804. tz = TimeZone.getTimeZone("Australia/Sydney");
  805. doTestTimeZone(tz);
  806. }
  807. private static void doTestTimeZone(final TimeZone tz) throws Exception
  808. {
  809. ColumnImpl col = new ColumnImpl(null, null, DataType.SHORT_DATE_TIME, 0, 0, 0) {
  810. @Override
  811. protected Calendar getCalendar() { return Calendar.getInstance(tz); }
  812. };
  813. SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd");
  814. df.setTimeZone(tz);
  815. long startDate = df.parse("2012.01.01").getTime();
  816. long endDate = df.parse("2013.01.01").getTime();
  817. Calendar curCal = Calendar.getInstance(tz);
  818. curCal.setTimeInMillis(startDate);
  819. SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
  820. sdf.setTimeZone(tz);
  821. while(curCal.getTimeInMillis() < endDate) {
  822. Date curDate = curCal.getTime();
  823. Date newDate = new Date(col.fromDateDouble(col.toDateDouble(curDate)));
  824. if(curDate.getTime() != newDate.getTime()) {
  825. assertEquals(sdf.format(curDate), sdf.format(newDate));
  826. }
  827. curCal.add(Calendar.MINUTE, 30);
  828. }
  829. }
  830. public void testToString()
  831. {
  832. RowImpl row = new RowImpl(new RowIdImpl(1, 1));
  833. row.put("id", 37);
  834. row.put("data", null);
  835. assertEquals("Row[1:1][{id=37,data=<null>}]", row.toString());
  836. }
  837. private static void checkRawValue(String expected, Object val)
  838. {
  839. if(expected != null) {
  840. assertTrue(ColumnImpl.isRawData(val));
  841. assertEquals(expected, val.toString());
  842. } else {
  843. assertNull(val);
  844. }
  845. }
  846. }