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 53KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686
  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.nio.channels.FileChannel;
  34. import java.sql.Types;
  35. import java.text.DateFormat;
  36. import java.text.SimpleDateFormat;
  37. import java.util.ArrayList;
  38. import java.util.Arrays;
  39. import java.util.Calendar;
  40. import java.util.Collections;
  41. import java.util.Date;
  42. import java.util.HashSet;
  43. import java.util.Iterator;
  44. import java.util.LinkedHashMap;
  45. import java.util.List;
  46. import java.util.Map;
  47. import java.util.Set;
  48. import java.util.TimeZone;
  49. import java.util.TreeSet;
  50. import java.util.UUID;
  51. import static com.healthmarketscience.jackcess.Database.*;
  52. import com.healthmarketscience.jackcess.complex.ComplexValueForeignKey;
  53. import com.healthmarketscience.jackcess.impl.ByteUtil;
  54. import com.healthmarketscience.jackcess.impl.ColumnImpl;
  55. import com.healthmarketscience.jackcess.impl.DatabaseImpl;
  56. import com.healthmarketscience.jackcess.impl.IndexData;
  57. import com.healthmarketscience.jackcess.impl.IndexImpl;
  58. import com.healthmarketscience.jackcess.impl.JetFormat;
  59. import static com.healthmarketscience.jackcess.impl.JetFormatTest.*;
  60. import com.healthmarketscience.jackcess.impl.RowIdImpl;
  61. import com.healthmarketscience.jackcess.impl.RowImpl;
  62. import com.healthmarketscience.jackcess.impl.TableImpl;
  63. import com.healthmarketscience.jackcess.util.LinkResolver;
  64. import com.healthmarketscience.jackcess.util.MemFileChannel;
  65. import com.healthmarketscience.jackcess.util.RowFilterTest;
  66. import junit.framework.TestCase;
  67. /**
  68. * @author Tim McCune
  69. */
  70. public class DatabaseTest extends TestCase {
  71. public static final TimeZone TEST_TZ =
  72. TimeZone.getTimeZone("America/New_York");
  73. static boolean _autoSync = Database.DEFAULT_AUTO_SYNC;
  74. public DatabaseTest(String name) throws Exception {
  75. super(name);
  76. }
  77. public static Database open(FileFormat fileFormat, File file)
  78. throws Exception
  79. {
  80. return open(fileFormat, file, false);
  81. }
  82. private static Database open(FileFormat fileFormat, File file,
  83. boolean inMem)
  84. throws Exception
  85. {
  86. FileChannel channel = (inMem ? MemFileChannel.newChannel(file, "r")
  87. : null);
  88. final Database db = new DatabaseBuilder(file).setReadOnly(true)
  89. .setAutoSync(_autoSync).setChannel(channel).open();
  90. assertEquals("Wrong JetFormat.",
  91. DatabaseImpl.getFileFormatDetails(fileFormat).getFormat(),
  92. ((DatabaseImpl)db).getFormat());
  93. assertEquals("Wrong FileFormat.", fileFormat, db.getFileFormat());
  94. return db;
  95. }
  96. public static Database open(TestDB testDB) throws Exception {
  97. return open(testDB.getExpectedFileFormat(), testDB.getFile());
  98. }
  99. public static Database openMem(TestDB testDB) throws Exception {
  100. return open(testDB.getExpectedFileFormat(), testDB.getFile(), true);
  101. }
  102. public static Database create(FileFormat fileFormat) throws Exception {
  103. return create(fileFormat, false);
  104. }
  105. public static Database create(FileFormat fileFormat, boolean keep)
  106. throws Exception
  107. {
  108. return create(fileFormat, keep, false);
  109. }
  110. public static Database createMem(FileFormat fileFormat) throws Exception {
  111. return create(fileFormat, false, true);
  112. }
  113. private static Database create(FileFormat fileFormat, boolean keep,
  114. boolean inMem)
  115. throws Exception
  116. {
  117. FileChannel channel = (inMem ? MemFileChannel.newChannel() : null);
  118. return new DatabaseBuilder(createTempFile(keep)).setFileFormat(fileFormat)
  119. .setAutoSync(_autoSync).setChannel(channel).create();
  120. }
  121. public static Database openCopy(TestDB testDB) throws Exception {
  122. return openCopy(testDB, false);
  123. }
  124. public static Database openCopy(TestDB testDB, boolean keep)
  125. throws Exception
  126. {
  127. return openCopy(testDB.getExpectedFileFormat(), testDB.getFile(), keep);
  128. }
  129. public static Database openCopy(FileFormat fileFormat, File file)
  130. throws Exception
  131. {
  132. return openCopy(fileFormat, file, false);
  133. }
  134. public static Database openCopy(FileFormat fileFormat, File file,
  135. boolean keep)
  136. throws Exception
  137. {
  138. File tmp = createTempFile(keep);
  139. copyFile(file, tmp);
  140. Database db = new DatabaseBuilder(tmp).setAutoSync(_autoSync).open();
  141. assertEquals("Wrong JetFormat.",
  142. DatabaseImpl.getFileFormatDetails(fileFormat).getFormat(),
  143. ((DatabaseImpl)db).getFormat());
  144. assertEquals("Wrong FileFormat.", fileFormat, db.getFileFormat());
  145. return db;
  146. }
  147. public void testInvalidTableDefs() throws Exception {
  148. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  149. Database db = create(fileFormat);
  150. try {
  151. ((DatabaseImpl)db).createTable("test", Collections.<ColumnBuilder>emptyList());
  152. fail("created table with no columns?");
  153. } catch(IllegalArgumentException e) {
  154. // success
  155. }
  156. try {
  157. new TableBuilder("test")
  158. .addColumn(new ColumnBuilder("A", DataType.TEXT))
  159. .addColumn(new ColumnBuilder("a", DataType.MEMO))
  160. .toTable(db);
  161. fail("created table with duplicate column names?");
  162. } catch(IllegalArgumentException e) {
  163. // success
  164. }
  165. try {
  166. new TableBuilder("test")
  167. .addColumn(new ColumnBuilder("A", DataType.TEXT)
  168. .setLengthInUnits(352))
  169. .toTable(db);
  170. fail("created table with invalid column length?");
  171. } catch(IllegalArgumentException e) {
  172. // success
  173. }
  174. try {
  175. new TableBuilder("test")
  176. .addColumn(new ColumnBuilder("A_" + createString(70), DataType.TEXT))
  177. .toTable(db);
  178. fail("created table with too long column name?");
  179. } catch(IllegalArgumentException e) {
  180. // success
  181. }
  182. new TableBuilder("test")
  183. .addColumn(new ColumnBuilder("A", DataType.TEXT))
  184. .toTable(db);
  185. try {
  186. new TableBuilder("Test")
  187. .addColumn(new ColumnBuilder("A", DataType.TEXT))
  188. .toTable(db);
  189. fail("create duplicate tables?");
  190. } catch(IllegalArgumentException e) {
  191. // success
  192. }
  193. db.close();
  194. }
  195. }
  196. public void testReadDeletedRows() throws Exception {
  197. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.DEL, true)) {
  198. Table table = open(testDB).getTable("Table");
  199. int rows = 0;
  200. while (table.getNextRow() != null) {
  201. rows++;
  202. }
  203. assertEquals(2, rows);
  204. table.getDatabase().close();
  205. }
  206. }
  207. public void testGetColumns() throws Exception {
  208. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  209. List<? extends Column> columns = open(testDB).getTable("Table1").getColumns();
  210. assertEquals(9, columns.size());
  211. checkColumn(columns, 0, "A", DataType.TEXT);
  212. checkColumn(columns, 1, "B", DataType.TEXT);
  213. checkColumn(columns, 2, "C", DataType.BYTE);
  214. checkColumn(columns, 3, "D", DataType.INT);
  215. checkColumn(columns, 4, "E", DataType.LONG);
  216. checkColumn(columns, 5, "F", DataType.DOUBLE);
  217. checkColumn(columns, 6, "G", DataType.SHORT_DATE_TIME);
  218. checkColumn(columns, 7, "H", DataType.MONEY);
  219. checkColumn(columns, 8, "I", DataType.BOOLEAN);
  220. }
  221. }
  222. static void checkColumn(List<? extends Column> columns, int columnNumber,
  223. String name, DataType dataType)
  224. throws Exception
  225. {
  226. Column column = columns.get(columnNumber);
  227. assertEquals(name, column.getName());
  228. assertEquals(dataType, column.getType());
  229. }
  230. public void testGetNextRow() throws Exception {
  231. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  232. final Database db = open(testDB);
  233. assertEquals(4, db.getTableNames().size());
  234. final Table table = db.getTable("Table1");
  235. Map<String, Object> row1 = table.getNextRow();
  236. Map<String, Object> row2 = table.getNextRow();
  237. if(!"abcdefg".equals(row1.get("A"))) {
  238. Map<String, Object> tmpRow = row1;
  239. row1 = row2;
  240. row2 = tmpRow;
  241. }
  242. checkTestDBTable1RowABCDEFG(testDB, table, row1);
  243. checkTestDBTable1RowA(testDB, table, row2);
  244. db.close();
  245. }
  246. }
  247. static void checkTestDBTable1RowABCDEFG(final TestDB testDB, final Table table, final Map<String, Object> row)
  248. throws IOException {
  249. assertEquals("testDB: " + testDB + "; table: " + table, "abcdefg", row.get("A"));
  250. assertEquals("hijklmnop", row.get("B"));
  251. assertEquals(new Byte((byte) 2), row.get("C"));
  252. assertEquals(new Short((short) 222), row.get("D"));
  253. assertEquals(new Integer(333333333), row.get("E"));
  254. assertEquals(new Double(444.555d), row.get("F"));
  255. final Calendar cal = Calendar.getInstance();
  256. cal.setTime((Date) row.get("G"));
  257. assertEquals(Calendar.SEPTEMBER, cal.get(Calendar.MONTH));
  258. assertEquals(21, cal.get(Calendar.DAY_OF_MONTH));
  259. assertEquals(1974, cal.get(Calendar.YEAR));
  260. assertEquals(0, cal.get(Calendar.HOUR_OF_DAY));
  261. assertEquals(0, cal.get(Calendar.MINUTE));
  262. assertEquals(0, cal.get(Calendar.SECOND));
  263. assertEquals(0, cal.get(Calendar.MILLISECOND));
  264. assertEquals(Boolean.TRUE, row.get("I"));
  265. }
  266. static void checkTestDBTable1RowA(final TestDB testDB, final Table table, final Map<String, Object> row)
  267. throws IOException {
  268. assertEquals("testDB: " + testDB + "; table: " + table, "a", row.get("A"));
  269. assertEquals("b", row.get("B"));
  270. assertEquals(new Byte((byte) 0), row.get("C"));
  271. assertEquals(new Short((short) 0), row.get("D"));
  272. assertEquals(new Integer(0), row.get("E"));
  273. assertEquals(new Double(0d), row.get("F"));
  274. final Calendar cal = Calendar.getInstance();
  275. cal.setTime((Date) row.get("G"));
  276. assertEquals(Calendar.DECEMBER, cal.get(Calendar.MONTH));
  277. assertEquals(12, cal.get(Calendar.DAY_OF_MONTH));
  278. assertEquals(1981, cal.get(Calendar.YEAR));
  279. assertEquals(0, cal.get(Calendar.HOUR_OF_DAY));
  280. assertEquals(0, cal.get(Calendar.MINUTE));
  281. assertEquals(0, cal.get(Calendar.SECOND));
  282. assertEquals(0, cal.get(Calendar.MILLISECOND));
  283. assertEquals(Boolean.FALSE, row.get("I"));
  284. }
  285. public void testCreate() throws Exception {
  286. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  287. Database db = create(fileFormat);
  288. assertEquals(0, db.getTableNames().size());
  289. db.close();
  290. }
  291. }
  292. public void testWriteAndRead() throws Exception {
  293. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  294. Database db = create(fileFormat);
  295. doTestWriteAndRead(db);
  296. db.close();
  297. }
  298. }
  299. public void testWriteAndReadInMem() throws Exception {
  300. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  301. Database db = createMem(fileFormat);
  302. doTestWriteAndRead(db);
  303. db.close();
  304. }
  305. }
  306. private static void doTestWriteAndRead(Database db) throws Exception {
  307. createTestTable(db);
  308. Object[] row = createTestRow();
  309. row[3] = null;
  310. Table table = db.getTable("Test");
  311. int count = 1000;
  312. for (int i = 0; i < count; i++) {
  313. table.addRow(row);
  314. }
  315. for (int i = 0; i < count; i++) {
  316. Map<String, Object> readRow = table.getNextRow();
  317. assertEquals(row[0], readRow.get("A"));
  318. assertEquals(row[1], readRow.get("B"));
  319. assertEquals(row[2], readRow.get("C"));
  320. assertEquals(row[3], readRow.get("D"));
  321. assertEquals(row[4], readRow.get("E"));
  322. assertEquals(row[5], readRow.get("F"));
  323. assertEquals(row[6], readRow.get("G"));
  324. assertEquals(row[7], readRow.get("H"));
  325. }
  326. }
  327. public void testWriteAndReadInBatch() throws Exception {
  328. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  329. Database db = create(fileFormat);
  330. createTestTable(db);
  331. int count = 1000;
  332. List<Object[]> rows = new ArrayList<Object[]>(count);
  333. Object[] row = createTestRow();
  334. for (int i = 0; i < count; i++) {
  335. rows.add(row);
  336. }
  337. Table table = db.getTable("Test");
  338. table.addRows(rows);
  339. for (int i = 0; i < count; i++) {
  340. Map<String, Object> readRow = table.getNextRow();
  341. assertEquals(row[0], readRow.get("A"));
  342. assertEquals(row[1], readRow.get("B"));
  343. assertEquals(row[2], readRow.get("C"));
  344. assertEquals(row[3], readRow.get("D"));
  345. assertEquals(row[4], readRow.get("E"));
  346. assertEquals(row[5], readRow.get("F"));
  347. assertEquals(row[6], readRow.get("G"));
  348. assertEquals(row[7], readRow.get("H"));
  349. }
  350. db.close();
  351. }
  352. }
  353. public void testDeleteCurrentRow() throws Exception {
  354. // make sure correct row is deleted
  355. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  356. Database db = create(fileFormat);
  357. createTestTable(db);
  358. Map<String,Object> row1 = createTestRowMap("Tim1");
  359. Map<String,Object> row2 = createTestRowMap("Tim2");
  360. Map<String,Object> row3 = createTestRowMap("Tim3");
  361. Table table = db.getTable("Test");
  362. @SuppressWarnings("unchecked")
  363. List<Map<String,Object>> rows = Arrays.asList(row1, row2, row3);
  364. table.addRowsFromMaps(rows);
  365. assertRowCount(3, table);
  366. table.reset();
  367. table.getNextRow();
  368. table.getNextRow();
  369. table.getDefaultCursor().deleteCurrentRow();
  370. table.reset();
  371. Map<String, Object> outRow = table.getNextRow();
  372. assertEquals("Tim1", outRow.get("A"));
  373. outRow = table.getNextRow();
  374. assertEquals("Tim3", outRow.get("A"));
  375. assertRowCount(2, table);
  376. // test multi row delete/add
  377. db = create(fileFormat);
  378. createTestTable(db);
  379. Object[] row = createTestRow();
  380. table = db.getTable("Test");
  381. for (int i = 0; i < 10; i++) {
  382. row[3] = i;
  383. table.addRow(row);
  384. }
  385. row[3] = 1974;
  386. assertRowCount(10, table);
  387. table.reset();
  388. table.getNextRow();
  389. table.getDefaultCursor().deleteCurrentRow();
  390. assertRowCount(9, table);
  391. table.reset();
  392. table.getNextRow();
  393. table.getDefaultCursor().deleteCurrentRow();
  394. assertRowCount(8, table);
  395. table.reset();
  396. for (int i = 0; i < 8; i++) {
  397. table.getNextRow();
  398. }
  399. table.getDefaultCursor().deleteCurrentRow();
  400. assertRowCount(7, table);
  401. table.addRow(row);
  402. assertRowCount(8, table);
  403. table.reset();
  404. for (int i = 0; i < 3; i++) {
  405. table.getNextRow();
  406. }
  407. table.getDefaultCursor().deleteCurrentRow();
  408. assertRowCount(7, table);
  409. table.reset();
  410. assertEquals(2, table.getNextRow().get("D"));
  411. db.close();
  412. }
  413. }
  414. public void testDeleteRow() throws Exception {
  415. // make sure correct row is deleted
  416. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  417. Database db = create(fileFormat);
  418. createTestTable(db);
  419. Table table = db.getTable("Test");
  420. for(int i = 0; i < 10; ++i) {
  421. table.addRowFromMap(createTestRowMap("Tim" + i));
  422. }
  423. assertRowCount(10, table);
  424. table.reset();
  425. List<Row> rows = RowFilterTest.toList(table);
  426. Row r1 = rows.remove(7);
  427. Row r2 = rows.remove(3);
  428. assertEquals(8, rows.size());
  429. assertSame(r2, table.deleteRow(r2));
  430. assertSame(r1, table.deleteRow(r1));
  431. assertTable(rows, table);
  432. table.deleteRow(r2);
  433. table.deleteRow(r1);
  434. assertTable(rows, table);
  435. }
  436. }
  437. public void testReadLongValue() throws Exception {
  438. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.TEST2, true)) {
  439. Database db = open(testDB);
  440. Table table = db.getTable("MSP_PROJECTS");
  441. Map<String, Object> row = table.getNextRow();
  442. 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"));
  443. assertEquals("T", row.get("PROJ_PROP_COMPANY"));
  444. assertEquals("Standard", row.get("PROJ_INFO_CAL_NAME"));
  445. assertEquals("Project1", row.get("PROJ_PROP_TITLE"));
  446. byte[] foundBinaryData = (byte[])row.get("RESERVED_BINARY_DATA");
  447. byte[] expectedBinaryData =
  448. toByteArray(new File("src/test/data/test2BinData.dat"));
  449. assertTrue(Arrays.equals(expectedBinaryData, foundBinaryData));
  450. db.close();
  451. }
  452. }
  453. public void testWriteLongValue() throws Exception {
  454. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  455. Database db = create(fileFormat);
  456. Table table =
  457. new TableBuilder("test")
  458. .addColumn(new ColumnBuilder("A", DataType.TEXT))
  459. .addColumn(new ColumnBuilder("B", DataType.MEMO))
  460. .addColumn(new ColumnBuilder("C", DataType.OLE))
  461. .toTable(db);
  462. String testStr = "This is a test";
  463. String longMemo = createString(2030);
  464. byte[] oleValue = toByteArray(new File("src/test/data/test2BinData.dat"));
  465. table.addRow(testStr, testStr, null);
  466. table.addRow(testStr, longMemo, oleValue);
  467. table.reset();
  468. Map<String, Object> row = table.getNextRow();
  469. assertEquals(testStr, row.get("A"));
  470. assertEquals(testStr, row.get("B"));
  471. assertNull(row.get("C"));
  472. row = table.getNextRow();
  473. assertEquals(testStr, row.get("A"));
  474. assertEquals(longMemo, row.get("B"));
  475. assertTrue(Arrays.equals(oleValue, (byte[])row.get("C")));
  476. db.close();
  477. }
  478. }
  479. public void testManyMemos() throws Exception {
  480. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  481. Database db = create(fileFormat);
  482. final int numColumns = 126;
  483. TableBuilder bigTableBuilder = new TableBuilder("test");
  484. for (int i = 0; i < numColumns; i++)
  485. {
  486. bigTableBuilder.addColumn(new ColumnBuilder("column_" + i, DataType.MEMO));
  487. }
  488. Table bigTable = bigTableBuilder.toTable(db);
  489. List<Object[]> expectedRows = new ArrayList<Object[]>();
  490. for (int j = 0; j < 3; j++)
  491. {
  492. Object[] rowData = new String[numColumns];
  493. for (int i = 0; i < numColumns; i++)
  494. {
  495. rowData[i] = "v_" + i + ";" + (j + 999);
  496. }
  497. expectedRows.add(rowData);
  498. bigTable.addRow(rowData);
  499. }
  500. String extra1 = createString(100);
  501. String extra2 = createString(2050);
  502. for (int j = 0; j < 1; j++)
  503. {
  504. Object[] rowData = new String[numColumns];
  505. for (int i = 0; i < numColumns; i++)
  506. {
  507. rowData[i] = "v_" + i + ";" + (j + 999) + extra2;
  508. }
  509. expectedRows.add(rowData);
  510. bigTable.addRow(rowData);
  511. }
  512. for (int j = 0; j < 2; j++)
  513. {
  514. Object[] rowData = new String[numColumns];
  515. for (int i = 0; i < numColumns; i++)
  516. {
  517. String tmp = "v_" + i + ";" + (j + 999);
  518. if((i % 3) == 0) {
  519. tmp += extra1;
  520. } else if((i % 7) == 0) {
  521. tmp += extra2;
  522. }
  523. rowData[i] = tmp;
  524. }
  525. expectedRows.add(rowData);
  526. bigTable.addRow(rowData);
  527. }
  528. bigTable.reset();
  529. Iterator<Object[]> expIter = expectedRows.iterator();
  530. for(Map<?,?> row : bigTable) {
  531. Object[] expectedRow = expIter.next();
  532. assertEquals(Arrays.asList(expectedRow),
  533. new ArrayList<Object>(row.values()));
  534. }
  535. db.close();
  536. }
  537. }
  538. public void testMissingFile() throws Exception {
  539. File bogusFile = new File("fooby-dooby.mdb");
  540. assertTrue(!bogusFile.exists());
  541. try {
  542. new DatabaseBuilder(bogusFile).setReadOnly(true).
  543. setAutoSync(_autoSync).open();
  544. fail("FileNotFoundException should have been thrown");
  545. } catch(FileNotFoundException e) {
  546. }
  547. assertTrue(!bogusFile.exists());
  548. }
  549. public void testReadWithDeletedCols() throws Exception {
  550. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.DEL_COL, true)) {
  551. Table table = open(testDB).getTable("Table1");
  552. Map<String, Object> expectedRow0 = new LinkedHashMap<String, Object>();
  553. expectedRow0.put("id", 0);
  554. expectedRow0.put("id2", 2);
  555. expectedRow0.put("data", "foo");
  556. expectedRow0.put("data2", "foo2");
  557. Map<String, Object> expectedRow1 = new LinkedHashMap<String, Object>();
  558. expectedRow1.put("id", 3);
  559. expectedRow1.put("id2", 5);
  560. expectedRow1.put("data", "bar");
  561. expectedRow1.put("data2", "bar2");
  562. int rowNum = 0;
  563. Map<String, Object> row = null;
  564. while ((row = table.getNextRow()) != null) {
  565. if(rowNum == 0) {
  566. assertEquals(expectedRow0, row);
  567. } else if(rowNum == 1) {
  568. assertEquals(expectedRow1, row);
  569. } else if(rowNum >= 2) {
  570. fail("should only have 2 rows");
  571. }
  572. rowNum++;
  573. }
  574. table.getDatabase().close();
  575. }
  576. }
  577. public void testCurrency() throws Exception {
  578. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  579. Database db = create(fileFormat);
  580. Table table = new TableBuilder("test")
  581. .addColumn(new ColumnBuilder("A", DataType.MONEY))
  582. .toTable(db);
  583. table.addRow(new BigDecimal("-2341234.03450"));
  584. table.addRow(37L);
  585. table.addRow("10000.45");
  586. table.reset();
  587. List<Object> foundValues = new ArrayList<Object>();
  588. Map<String, Object> row = null;
  589. while((row = table.getNextRow()) != null) {
  590. foundValues.add(row.get("A"));
  591. }
  592. assertEquals(Arrays.asList(
  593. new BigDecimal("-2341234.0345"),
  594. new BigDecimal("37.0000"),
  595. new BigDecimal("10000.4500")),
  596. foundValues);
  597. try {
  598. table.addRow(new BigDecimal("342523234145343543.3453"));
  599. fail("IOException should have been thrown");
  600. } catch(IOException e) {
  601. // ignored
  602. }
  603. db.close();
  604. }
  605. }
  606. public void testGUID() throws Exception
  607. {
  608. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  609. Database db = create(fileFormat);
  610. Table table = new TableBuilder("test")
  611. .addColumn(new ColumnBuilder("A", DataType.GUID))
  612. .toTable(db);
  613. table.addRow("{32A59F01-AA34-3E29-453F-4523453CD2E6}");
  614. table.addRow("{32a59f01-aa34-3e29-453f-4523453cd2e6}");
  615. table.addRow("{11111111-1111-1111-1111-111111111111}");
  616. table.addRow(" {FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF} ");
  617. table.addRow(UUID.fromString("32a59f01-1234-3e29-4aaf-4523453cd2e6"));
  618. table.reset();
  619. List<Object> foundValues = new ArrayList<Object>();
  620. Map<String, Object> row = null;
  621. while((row = table.getNextRow()) != null) {
  622. foundValues.add(row.get("A"));
  623. }
  624. assertEquals(Arrays.asList(
  625. "{32A59F01-AA34-3E29-453F-4523453CD2E6}",
  626. "{32A59F01-AA34-3E29-453F-4523453CD2E6}",
  627. "{11111111-1111-1111-1111-111111111111}",
  628. "{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}",
  629. "{32A59F01-1234-3E29-4AAF-4523453CD2E6}"),
  630. foundValues);
  631. try {
  632. table.addRow("3245234");
  633. fail("IOException should have been thrown");
  634. } catch(IOException e) {
  635. // ignored
  636. }
  637. db.close();
  638. }
  639. }
  640. public void testNumeric() throws Exception
  641. {
  642. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  643. Database db = create(fileFormat);
  644. ColumnBuilder col = new ColumnBuilder("A", DataType.NUMERIC)
  645. .setScale(4).setPrecision(8).toColumn();
  646. assertTrue(col.getType().isVariableLength());
  647. Table table = new TableBuilder("test")
  648. .addColumn(col)
  649. .addColumn(new ColumnBuilder("B", DataType.NUMERIC)
  650. .setScale(8).setPrecision(28))
  651. .toTable(db);
  652. table.addRow(new BigDecimal("-1234.03450"),
  653. new BigDecimal("23923434453436.36234219"));
  654. table.addRow(37L, 37L);
  655. table.addRow("1000.45", "-3452345321000");
  656. table.reset();
  657. List<Object> foundSmallValues = new ArrayList<Object>();
  658. List<Object> foundBigValues = new ArrayList<Object>();
  659. Map<String, Object> row = null;
  660. while((row = table.getNextRow()) != null) {
  661. foundSmallValues.add(row.get("A"));
  662. foundBigValues.add(row.get("B"));
  663. }
  664. assertEquals(Arrays.asList(
  665. new BigDecimal("-1234.0345"),
  666. new BigDecimal("37.0000"),
  667. new BigDecimal("1000.4500")),
  668. foundSmallValues);
  669. assertEquals(Arrays.asList(
  670. new BigDecimal("23923434453436.36234219"),
  671. new BigDecimal("37.00000000"),
  672. new BigDecimal("-3452345321000.00000000")),
  673. foundBigValues);
  674. try {
  675. table.addRow(new BigDecimal("3245234.234"),
  676. new BigDecimal("3245234.234"));
  677. fail("IOException should have been thrown");
  678. } catch(IOException e) {
  679. // ignored
  680. }
  681. db.close();
  682. }
  683. }
  684. public void testFixedNumeric() throws Exception
  685. {
  686. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.FIXED_NUMERIC)) {
  687. Database db = openCopy(testDB);
  688. Table t = db.getTable("test");
  689. boolean first = true;
  690. for(Column col : t.getColumns()) {
  691. if(first) {
  692. assertTrue(col.isVariableLength());
  693. assertEquals(DataType.MEMO, col.getType());
  694. first = false;
  695. } else {
  696. assertFalse(col.isVariableLength());
  697. assertEquals(DataType.NUMERIC, col.getType());
  698. }
  699. }
  700. Map<String, Object> row = t.getNextRow();
  701. assertEquals("some data", row.get("col1"));
  702. assertEquals(new BigDecimal("1"), row.get("col2"));
  703. assertEquals(new BigDecimal("0"), row.get("col3"));
  704. assertEquals(new BigDecimal("0"), row.get("col4"));
  705. assertEquals(new BigDecimal("4"), row.get("col5"));
  706. assertEquals(new BigDecimal("-1"), row.get("col6"));
  707. assertEquals(new BigDecimal("1"), row.get("col7"));
  708. Object[] tmpRow = new Object[]{
  709. "foo", new BigDecimal("1"), new BigDecimal(3), new BigDecimal("13"),
  710. new BigDecimal("-17"), new BigDecimal("0"), new BigDecimal("8734")};
  711. t.addRow(tmpRow);
  712. t.reset();
  713. t.getNextRow();
  714. row = t.getNextRow();
  715. assertEquals(tmpRow[0], row.get("col1"));
  716. assertEquals(tmpRow[1], row.get("col2"));
  717. assertEquals(tmpRow[2], row.get("col3"));
  718. assertEquals(tmpRow[3], row.get("col4"));
  719. assertEquals(tmpRow[4], row.get("col5"));
  720. assertEquals(tmpRow[5], row.get("col6"));
  721. assertEquals(tmpRow[6], row.get("col7"));
  722. db.close();
  723. }
  724. }
  725. public void testMultiPageTableDef() throws Exception
  726. {
  727. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  728. List<? extends Column> columns = open(testDB).getTable("Table2").getColumns();
  729. assertEquals(89, columns.size());
  730. }
  731. }
  732. public void testOverflow() throws Exception
  733. {
  734. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.OVERFLOW, true)) {
  735. Database mdb = open(testDB);
  736. Table table = mdb.getTable("Table1");
  737. // 7 rows, 3 and 5 are overflow
  738. table.getNextRow();
  739. table.getNextRow();
  740. Map<String, Object> row = table.getNextRow();
  741. assertEquals(Arrays.<Object>asList(
  742. null, "row3col3", null, null, null, null, null,
  743. "row3col9", null),
  744. new ArrayList<Object>(row.values()));
  745. table.getNextRow();
  746. row = table.getNextRow();
  747. assertEquals(Arrays.<Object>asList(
  748. null, "row5col2", null, null, null, null, null, null,
  749. null),
  750. new ArrayList<Object>(row.values()));
  751. table.reset();
  752. assertRowCount(7, table);
  753. mdb.close();
  754. }
  755. }
  756. public void testLongValueAsMiddleColumn() throws Exception
  757. {
  758. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  759. Database db = create(fileFormat);
  760. Table newTable = new TableBuilder("NewTable")
  761. .addColumn(new ColumnBuilder("a").setSQLType(Types.INTEGER))
  762. .addColumn(new ColumnBuilder("b").setSQLType(Types.LONGVARCHAR))
  763. .addColumn(new ColumnBuilder("c").setSQLType(Types.VARCHAR))
  764. .toTable(db);
  765. String lval = createString(2000); // "--2000 chars long text--";
  766. String tval = createString(40); // "--40chars long text--";
  767. newTable.addRow(new Integer(1), lval, tval);
  768. newTable = db.getTable("NewTable");
  769. Map<String, Object> readRow = newTable.getNextRow();
  770. assertEquals(new Integer(1), readRow.get("a"));
  771. assertEquals(lval, readRow.get("b"));
  772. assertEquals(tval, readRow.get("c"));
  773. db.close();
  774. }
  775. }
  776. public void testUsageMapPromotion() throws Exception {
  777. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.PROMOTION)) {
  778. Database db = openCopy(testDB);
  779. Table t = db.getTable("jobDB1");
  780. assertTrue(((TableImpl)t).getOwnedPagesCursor().getUsageMap().toString()
  781. .startsWith("InlineHandler"));
  782. String lval = createNonAsciiString(255); // "--255 chars long text--";
  783. for(int i = 0; i < 1000; ++i) {
  784. t.addRow(i, 13, 57, lval, lval, lval, lval, lval, lval, 47.0d);
  785. }
  786. Set<Integer> ids = new HashSet<Integer>();
  787. for(Map<String,Object> row : t) {
  788. ids.add((Integer)row.get("ID"));
  789. }
  790. assertEquals(1000, ids.size());
  791. assertTrue(((TableImpl)t).getOwnedPagesCursor().getUsageMap().toString()
  792. .startsWith("ReferenceHandler"));
  793. db.close();
  794. }
  795. }
  796. public void testLargeTableDef() throws Exception {
  797. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  798. Database db = create(fileFormat);
  799. final int numColumns = 90;
  800. List<ColumnBuilder> columns = new ArrayList<ColumnBuilder>();
  801. List<String> colNames = new ArrayList<String>();
  802. for(int i = 0; i < numColumns; ++i) {
  803. String colName = "MyColumnName" + i;
  804. colNames.add(colName);
  805. columns.add(new ColumnBuilder(colName, DataType.TEXT).toColumn());
  806. }
  807. ((DatabaseImpl)db).createTable("test", columns);
  808. Table t = db.getTable("test");
  809. List<String> row = new ArrayList<String>();
  810. Map<String,Object> expectedRowData = new LinkedHashMap<String, Object>();
  811. for(int i = 0; i < numColumns; ++i) {
  812. String value = "" + i + " some row data";
  813. row.add(value);
  814. expectedRowData.put(colNames.get(i), value);
  815. }
  816. t.addRow(row.toArray());
  817. t.reset();
  818. assertEquals(expectedRowData, t.getNextRow());
  819. db.close();
  820. }
  821. }
  822. public void testAutoNumber() throws Exception {
  823. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  824. Database db = create(fileFormat);
  825. Table table = new TableBuilder("test")
  826. .addColumn(new ColumnBuilder("a", DataType.LONG)
  827. .setAutoNumber(true))
  828. .addColumn(new ColumnBuilder("b", DataType.TEXT))
  829. .toTable(db);
  830. doTestAutoNumber(table);
  831. db.close();
  832. }
  833. }
  834. public void testAutoNumberPK() throws Exception {
  835. for (final TestDB testDB : SUPPORTED_DBS_TEST) {
  836. Database db = openCopy(testDB);
  837. Table table = db.getTable("Table3");
  838. doTestAutoNumber(table);
  839. db.close();
  840. }
  841. }
  842. private void doTestAutoNumber(Table table) throws Exception
  843. {
  844. Object[] row = {null, "row1"};
  845. assertSame(row, table.addRow(row));
  846. assertEquals(1, ((Integer)row[0]).intValue());
  847. row = table.addRow(13, "row2");
  848. assertEquals(2, ((Integer)row[0]).intValue());
  849. row = table.addRow("flubber", "row3");
  850. assertEquals(3, ((Integer)row[0]).intValue());
  851. table.reset();
  852. row = table.addRow(Column.AUTO_NUMBER, "row4");
  853. assertEquals(4, ((Integer)row[0]).intValue());
  854. row = table.addRow(Column.AUTO_NUMBER, "row5");
  855. assertEquals(5, ((Integer)row[0]).intValue());
  856. Object[] smallRow = {Column.AUTO_NUMBER};
  857. row = table.addRow(smallRow);
  858. assertNotSame(row, smallRow);
  859. assertEquals(6, ((Integer)row[0]).intValue());
  860. table.reset();
  861. List<? extends Map<String, Object>> expectedRows =
  862. createExpectedTable(
  863. createExpectedRow(
  864. "a", 1,
  865. "b", "row1"),
  866. createExpectedRow(
  867. "a", 2,
  868. "b", "row2"),
  869. createExpectedRow(
  870. "a", 3,
  871. "b", "row3"),
  872. createExpectedRow(
  873. "a", 4,
  874. "b", "row4"),
  875. createExpectedRow(
  876. "a", 5,
  877. "b", "row5"),
  878. createExpectedRow(
  879. "a", 6,
  880. "b", null));
  881. assertTable(expectedRows, table);
  882. }
  883. public void testWriteAndReadDate() throws Exception {
  884. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  885. Database db = create(fileFormat);
  886. Table table = new TableBuilder("test")
  887. .addColumn(new ColumnBuilder("name", DataType.TEXT))
  888. .addColumn(new ColumnBuilder("date", DataType.SHORT_DATE_TIME))
  889. .toTable(db);
  890. // since jackcess does not really store millis, shave them off before
  891. // storing the current date/time
  892. long curTimeNoMillis = (System.currentTimeMillis() / 1000L);
  893. curTimeNoMillis *= 1000L;
  894. DateFormat df = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
  895. List<Date> dates =
  896. new ArrayList<Date>(
  897. Arrays.asList(
  898. df.parse("19801231 00:00:00"),
  899. df.parse("19930513 14:43:27"),
  900. null,
  901. df.parse("20210102 02:37:00"),
  902. new Date(curTimeNoMillis)));
  903. Calendar c = Calendar.getInstance();
  904. for(int year = 1801; year < 2050; year +=3) {
  905. for(int month = 0; month <= 12; ++month) {
  906. for(int day = 1; day < 29; day += 3) {
  907. c.clear();
  908. c.set(Calendar.YEAR, year);
  909. c.set(Calendar.MONTH, month);
  910. c.set(Calendar.DAY_OF_MONTH, day);
  911. dates.add(c.getTime());
  912. }
  913. }
  914. }
  915. for(Date d : dates) {
  916. table.addRow("row " + d, d);
  917. }
  918. List<Date> foundDates = new ArrayList<Date>();
  919. for(Map<String,Object> row : table) {
  920. foundDates.add((Date)row.get("date"));
  921. }
  922. assertEquals(dates.size(), foundDates.size());
  923. for(int i = 0; i < dates.size(); ++i) {
  924. Date expected = dates.get(i);
  925. Date found = foundDates.get(i);
  926. assertSameDate(expected, found);
  927. }
  928. db.close();
  929. }
  930. }
  931. public void testSystemTable() throws Exception
  932. {
  933. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  934. Database db = create(fileFormat);
  935. Set<String> sysTables = new TreeSet<String>(
  936. String.CASE_INSENSITIVE_ORDER);
  937. sysTables.addAll(
  938. Arrays.asList("MSysObjects", "MSysQueries", "MSysACES",
  939. "MSysRelationships"));
  940. if (fileFormat.ordinal() < FileFormat.V2003.ordinal()) {
  941. assertNotNull("file format: " + fileFormat, db.getSystemTable("MSysAccessObjects"));
  942. sysTables.add("MSysAccessObjects");
  943. } else {
  944. // v2003+ template files have no "MSysAccessObjects" table
  945. assertNull("file format: " + fileFormat, db.getSystemTable("MSysAccessObjects"));
  946. sysTables.addAll(
  947. Arrays.asList("MSysNavPaneGroupCategories",
  948. "MSysNavPaneGroups", "MSysNavPaneGroupToObjects",
  949. "MSysNavPaneObjectIDs", "MSysAccessStorage"));
  950. if(fileFormat.ordinal() >= FileFormat.V2007.ordinal()) {
  951. sysTables.addAll(
  952. Arrays.asList(
  953. "MSysComplexColumns", "MSysComplexType_Attachment",
  954. "MSysComplexType_Decimal", "MSysComplexType_GUID",
  955. "MSysComplexType_IEEEDouble", "MSysComplexType_IEEESingle",
  956. "MSysComplexType_Long", "MSysComplexType_Short",
  957. "MSysComplexType_Text", "MSysComplexType_UnsignedByte"));
  958. }
  959. if(fileFormat.ordinal() >= FileFormat.V2010.ordinal()) {
  960. sysTables.add("f_12D7448B56564D8AAE333BCC9B3718E5_Data");
  961. sysTables.add("MSysResources");
  962. }
  963. }
  964. assertEquals(sysTables, db.getSystemTableNames());
  965. assertNotNull(db.getSystemTable("MSysObjects"));
  966. assertNotNull(db.getSystemTable("MSysQueries"));
  967. assertNotNull(db.getSystemTable("MSysACES"));
  968. assertNotNull(db.getSystemTable("MSysRelationships"));
  969. assertNull(db.getSystemTable("MSysBogus"));
  970. db.close();
  971. }
  972. }
  973. public void testUpdateRow() throws Exception
  974. {
  975. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  976. Database db = create(fileFormat);
  977. Table t = new TableBuilder("test")
  978. .addColumn(new ColumnBuilder("name", DataType.TEXT))
  979. .addColumn(new ColumnBuilder("id", DataType.LONG)
  980. .setAutoNumber(true))
  981. .addColumn(new ColumnBuilder("data", DataType.TEXT)
  982. .setLength(JetFormat.TEXT_FIELD_MAX_LENGTH))
  983. .toTable(db);
  984. for(int i = 0; i < 10; ++i) {
  985. t.addRow("row" + i, Column.AUTO_NUMBER, "initial data");
  986. }
  987. Cursor c = CursorBuilder.createCursor(t);
  988. c.reset();
  989. c.moveNextRows(2);
  990. Map<String,Object> row = c.getCurrentRow();
  991. assertEquals(createExpectedRow("name", "row1",
  992. "id", 2,
  993. "data", "initial data"),
  994. row);
  995. Map<String,Object> newRow = createExpectedRow(
  996. "name", Column.KEEP_VALUE,
  997. "id", Column.AUTO_NUMBER,
  998. "data", "new data");
  999. assertSame(newRow, c.updateCurrentRowFromMap(newRow));
  1000. assertEquals(createExpectedRow("name", "row1",
  1001. "id", 2,
  1002. "data", "new data"),
  1003. newRow);
  1004. c.moveNextRows(3);
  1005. row = c.getCurrentRow();
  1006. assertEquals(createExpectedRow("name", "row4",
  1007. "id", 5,
  1008. "data", "initial data"),
  1009. row);
  1010. c.updateCurrentRow(Column.KEEP_VALUE, Column.AUTO_NUMBER, "a larger amount of new data");
  1011. c.reset();
  1012. c.moveNextRows(2);
  1013. row = c.getCurrentRow();
  1014. assertEquals(createExpectedRow("name", "row1",
  1015. "id", 2,
  1016. "data", "new data"),
  1017. row);
  1018. c.moveNextRows(3);
  1019. row = c.getCurrentRow();
  1020. assertEquals(createExpectedRow("name", "row4",
  1021. "id", 5,
  1022. "data", "a larger amount of new data"),
  1023. row);
  1024. t.reset();
  1025. String str = createString(100);
  1026. for(int i = 10; i < 50; ++i) {
  1027. t.addRow("row" + i, Column.AUTO_NUMBER, "big data_" + str);
  1028. }
  1029. c.reset();
  1030. c.moveNextRows(9);
  1031. row = c.getCurrentRow();
  1032. assertEquals(createExpectedRow("name", "row8",
  1033. "id", 9,
  1034. "data", "initial data"),
  1035. row);
  1036. String newText = "updated big data_" + createString(200);
  1037. c.setCurrentRowValue(t.getColumn("data"), newText);
  1038. c.reset();
  1039. c.moveNextRows(9);
  1040. row = c.getCurrentRow();
  1041. assertEquals(createExpectedRow("name", "row8",
  1042. "id", 9,
  1043. "data", newText),
  1044. row);
  1045. List<Row> rows = RowFilterTest.toList(t);
  1046. assertEquals(50, rows.size());
  1047. for(Row r : rows) {
  1048. r.put("data", "final data " + r.get("id"));
  1049. }
  1050. for(Row r : rows) {
  1051. assertSame(r, t.updateRow(r));
  1052. }
  1053. t.reset();
  1054. for(Row r : t) {
  1055. assertEquals("final data " + r.get("id"), r.get("data"));
  1056. }
  1057. db.close();
  1058. }
  1059. }
  1060. public void testFixedText() throws Exception
  1061. {
  1062. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.FIXED_TEXT)) {
  1063. Database db = openCopy(testDB);
  1064. Table t = db.getTable("users");
  1065. Column c = t.getColumn("c_flag_");
  1066. assertEquals(DataType.TEXT, c.getType());
  1067. assertEquals(false, c.isVariableLength());
  1068. assertEquals(2, c.getLength());
  1069. Map<String,Object> row = t.getNextRow();
  1070. assertEquals("N", row.get("c_flag_"));
  1071. t.addRow(3, "testFixedText", "boo", "foo", "bob", 3, 5, 9, "Y",
  1072. new Date());
  1073. t.getNextRow();
  1074. row = t.getNextRow();
  1075. assertEquals("testFixedText", row.get("c_user_login"));
  1076. assertEquals("Y", row.get("c_flag_"));
  1077. db.close();
  1078. }
  1079. }
  1080. public void testDbSortOrder() throws Exception {
  1081. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  1082. Database db = open(testDB);
  1083. assertEquals(((DatabaseImpl)db).getFormat().DEFAULT_SORT_ORDER,
  1084. ((DatabaseImpl)db).getDefaultSortOrder());
  1085. db.close();
  1086. }
  1087. }
  1088. public void testUnsupportedColumns() throws Exception {
  1089. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.UNSUPPORTED)) {
  1090. Database db = open(testDB);
  1091. Table t = db.getTable("Test");
  1092. Column varCol = t.getColumn("UnknownVar");
  1093. assertEquals(DataType.UNSUPPORTED_VARLEN, varCol.getType());
  1094. Column fixCol = t.getColumn("UnknownFix");
  1095. assertEquals(DataType.UNSUPPORTED_FIXEDLEN, fixCol.getType());
  1096. List<String> varVals = Arrays.asList(
  1097. "RawData: FF FE 73 6F 6D 65 64 61 74 61",
  1098. "RawData: FF FE 6F 74 68 65 72 20 64 61 74 61",
  1099. null);
  1100. List<String> fixVals = Arrays.asList("RawData: 37 00 00 00",
  1101. "RawData: F3 FF FF FF",
  1102. "RawData: 02 00 00 00");
  1103. int idx = 0;
  1104. for(Map<String,Object> row : t) {
  1105. checkRawValue(varVals.get(idx), varCol.getRowValue(row));
  1106. checkRawValue(fixVals.get(idx), fixCol.getRowValue(row));
  1107. ++idx;
  1108. }
  1109. db.close();
  1110. }
  1111. }
  1112. public void testLinkedTables() throws Exception {
  1113. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.LINKED)) {
  1114. Database db = openCopy(testDB);
  1115. try {
  1116. db.getTable("Table2");
  1117. fail("FileNotFoundException should have been thrown");
  1118. } catch(FileNotFoundException e) {
  1119. // success
  1120. }
  1121. assertTrue(db.getLinkedDatabases().isEmpty());
  1122. final String linkeeDbName = "Z:\\jackcess_test\\linkeeTest.accdb";
  1123. final File linkeeFile = new File("src/test/data/linkeeTest.accdb");
  1124. db.setLinkResolver(new LinkResolver() {
  1125. public Database resolveLinkedDatabase(Database linkerdb, String dbName)
  1126. throws IOException {
  1127. assertEquals(linkeeDbName, dbName);
  1128. return DatabaseBuilder.open(linkeeFile);
  1129. }
  1130. });
  1131. Table t2 = db.getTable("Table2");
  1132. assertEquals(1, db.getLinkedDatabases().size());
  1133. Database linkeeDb = db.getLinkedDatabases().get(linkeeDbName);
  1134. assertNotNull(linkeeDb);
  1135. assertEquals(linkeeFile, linkeeDb.getFile());
  1136. List<? extends Map<String, Object>> expectedRows =
  1137. createExpectedTable(
  1138. createExpectedRow(
  1139. "ID", 1,
  1140. "Field1", "bar"));
  1141. assertTable(expectedRows, t2);
  1142. db.createLinkedTable("FooTable", linkeeDbName, "Table2");
  1143. Table t3 = db.getTable("FooTable");
  1144. assertEquals(1, db.getLinkedDatabases().size());
  1145. expectedRows =
  1146. createExpectedTable(
  1147. createExpectedRow(
  1148. "ID", 1,
  1149. "Field1", "buzz"));
  1150. assertTable(expectedRows, t3);
  1151. db.close();
  1152. }
  1153. }
  1154. public void testTimeZone() throws Exception
  1155. {
  1156. TimeZone tz = TimeZone.getTimeZone("America/New_York");
  1157. doTestTimeZone(tz);
  1158. tz = TimeZone.getTimeZone("Australia/Sydney");
  1159. doTestTimeZone(tz);
  1160. }
  1161. private static void doTestTimeZone(final TimeZone tz) throws Exception
  1162. {
  1163. ColumnImpl col = new ColumnImpl(null, DataType.SHORT_DATE_TIME, 0, 0, 0) {
  1164. @Override
  1165. protected Calendar getCalendar() { return Calendar.getInstance(tz); }
  1166. };
  1167. SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd");
  1168. df.setTimeZone(tz);
  1169. long startDate = df.parse("2012.01.01").getTime();
  1170. long endDate = df.parse("2013.01.01").getTime();
  1171. Calendar curCal = Calendar.getInstance(tz);
  1172. curCal.setTimeInMillis(startDate);
  1173. SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
  1174. sdf.setTimeZone(tz);
  1175. while(curCal.getTimeInMillis() < endDate) {
  1176. Date curDate = curCal.getTime();
  1177. Date newDate = new Date(col.fromDateDouble(col.toDateDouble(curDate)));
  1178. if(curDate.getTime() != newDate.getTime()) {
  1179. assertEquals(sdf.format(curDate), sdf.format(newDate));
  1180. }
  1181. curCal.add(Calendar.MINUTE, 30);
  1182. }
  1183. }
  1184. private void checkRawValue(String expected, Object val)
  1185. {
  1186. if(expected != null) {
  1187. assertTrue(ColumnImpl.isRawData(val));
  1188. assertEquals(expected, val.toString());
  1189. } else {
  1190. assertNull(val);
  1191. }
  1192. }
  1193. static Object[] createTestRow(String col1Val) {
  1194. return new Object[] {col1Val, "R", "McCune", 1234, (byte) 0xad, 555.66d,
  1195. 777.88f, (short) 999, new Date()};
  1196. }
  1197. static Object[] createTestRow() {
  1198. return createTestRow("Tim");
  1199. }
  1200. static Map<String,Object> createTestRowMap(String col1Val) {
  1201. return createExpectedRow("A", col1Val, "B", "R", "C", "McCune",
  1202. "D", 1234, "E", (byte) 0xad, "F", 555.66d,
  1203. "G", 777.88f, "H", (short) 999, "I", new Date());
  1204. }
  1205. static void createTestTable(Database db) throws Exception {
  1206. new TableBuilder("test")
  1207. .addColumn(new ColumnBuilder("A", DataType.TEXT))
  1208. .addColumn(new ColumnBuilder("B", DataType.TEXT))
  1209. .addColumn(new ColumnBuilder("C", DataType.TEXT))
  1210. .addColumn(new ColumnBuilder("D", DataType.LONG))
  1211. .addColumn(new ColumnBuilder("E", DataType.BYTE))
  1212. .addColumn(new ColumnBuilder("F", DataType.DOUBLE))
  1213. .addColumn(new ColumnBuilder("G", DataType.FLOAT))
  1214. .addColumn(new ColumnBuilder("H", DataType.INT))
  1215. .addColumn(new ColumnBuilder("I", DataType.SHORT_DATE_TIME))
  1216. .toTable(db);
  1217. }
  1218. public static String createString(int len) {
  1219. return createString(len, 'a');
  1220. }
  1221. static String createNonAsciiString(int len) {
  1222. return createString(len, '\u00C0');
  1223. }
  1224. private static String createString(int len, char firstChar) {
  1225. StringBuilder builder = new StringBuilder(len);
  1226. for(int i = 0; i < len; ++i) {
  1227. builder.append((char)(firstChar + (i % 26)));
  1228. }
  1229. return builder.toString();
  1230. }
  1231. static void assertRowCount(int expectedRowCount, Table table)
  1232. throws Exception
  1233. {
  1234. assertEquals(expectedRowCount, countRows(table));
  1235. assertEquals(expectedRowCount, table.getRowCount());
  1236. }
  1237. public static int countRows(Table table) throws Exception {
  1238. int rtn = 0;
  1239. for(Map<String, Object> row : CursorBuilder.createCursor(table)) {
  1240. rtn++;
  1241. }
  1242. return rtn;
  1243. }
  1244. public static void assertTable(
  1245. List<? extends Map<String, Object>> expectedTable,
  1246. Table table)
  1247. throws IOException
  1248. {
  1249. assertCursor(expectedTable, CursorBuilder.createCursor(table));
  1250. }
  1251. public static void assertCursor(
  1252. List<? extends Map<String, Object>> expectedTable,
  1253. Cursor cursor)
  1254. {
  1255. List<Map<String, Object>> foundTable =
  1256. new ArrayList<Map<String, Object>>();
  1257. for(Map<String, Object> row : cursor) {
  1258. foundTable.add(row);
  1259. }
  1260. assertEquals(expectedTable, foundTable);
  1261. }
  1262. public static RowImpl createExpectedRow(Object... rowElements) {
  1263. RowImpl row = new RowImpl((RowIdImpl)null);
  1264. for(int i = 0; i < rowElements.length; i += 2) {
  1265. row.put((String)rowElements[i],
  1266. rowElements[i + 1]);
  1267. }
  1268. return row;
  1269. }
  1270. @SuppressWarnings("unchecked")
  1271. public static List<Row> createExpectedTable(Row... rows) {
  1272. return Arrays.<Row>asList(rows);
  1273. }
  1274. static void dumpDatabase(Database mdb) throws Exception {
  1275. dumpDatabase(mdb, false);
  1276. }
  1277. static void dumpDatabase(Database mdb, boolean systemTables)
  1278. throws Exception
  1279. {
  1280. dumpDatabase(mdb, systemTables, new PrintWriter(System.out, true));
  1281. }
  1282. static void dumpTable(Table table) throws Exception {
  1283. dumpTable(table, new PrintWriter(System.out, true));
  1284. }
  1285. static void dumpDatabase(Database mdb, boolean systemTables,
  1286. PrintWriter writer) throws Exception
  1287. {
  1288. writer.println("DATABASE:");
  1289. for(Table table : mdb) {
  1290. dumpTable(table, writer);
  1291. }
  1292. if(systemTables) {
  1293. for(String sysTableName : mdb.getSystemTableNames()) {
  1294. dumpTable(mdb.getSystemTable(sysTableName), writer);
  1295. }
  1296. }
  1297. }
  1298. static void dumpTable(Table table, PrintWriter writer) throws Exception {
  1299. // make sure all indexes are read
  1300. for(Index index : table.getIndexes()) {
  1301. ((IndexImpl)index).initialize();
  1302. }
  1303. writer.println("TABLE: " + table.getName());
  1304. List<String> colNames = new ArrayList<String>();
  1305. for(Column col : table.getColumns()) {
  1306. colNames.add(col.getName());
  1307. }
  1308. writer.println("COLUMNS: " + colNames);
  1309. for(Map<String, Object> row : CursorBuilder.createCursor(table)) {
  1310. writer.println(massageRow(row));
  1311. }
  1312. }
  1313. private static Map<String,Object> massageRow(Map<String, Object> row)
  1314. throws IOException
  1315. {
  1316. for(Map.Entry<String, Object> entry : row.entrySet()) {
  1317. Object v = entry.getValue();
  1318. if(v instanceof byte[]) {
  1319. // make byte[] printable
  1320. byte[] bv = (byte[])v;
  1321. entry.setValue(ByteUtil.toHexString(ByteBuffer.wrap(bv), bv.length));
  1322. } else if(v instanceof ComplexValueForeignKey) {
  1323. // deref complex values
  1324. String str = "ComplexValue(" + v + ")" +
  1325. ((ComplexValueForeignKey)v).getValues();
  1326. entry.setValue(str);
  1327. }
  1328. }
  1329. return row;
  1330. }
  1331. static void dumpIndex(Index index) throws Exception {
  1332. dumpIndex(index, new PrintWriter(System.out, true));
  1333. }
  1334. static void dumpIndex(Index index, PrintWriter writer) throws Exception {
  1335. writer.println("INDEX: " + index);
  1336. IndexData.EntryCursor ec = ((IndexImpl)index).cursor();
  1337. IndexData.Entry lastE = ec.getLastEntry();
  1338. IndexData.Entry e = null;
  1339. while((e = ec.getNextEntry()) != lastE) {
  1340. writer.println(e);
  1341. }
  1342. }
  1343. static void assertSameDate(Date expected, Date found)
  1344. {
  1345. if(expected == found) {
  1346. return;
  1347. }
  1348. if((expected == null) || (found == null)) {
  1349. throw new AssertionError("Expected " + expected + ", found " + found);
  1350. }
  1351. long expTime = expected.getTime();
  1352. long foundTime = found.getTime();
  1353. // there are some rounding issues due to dates being stored as doubles,
  1354. // but it results in a 1 millisecond difference, so i'm not going to worry
  1355. // about it
  1356. if((expTime != foundTime) && (Math.abs(expTime - foundTime) > 1)) {
  1357. throw new AssertionError("Expected " + expTime + " (" + expected +
  1358. "), found " + foundTime + " (" + found + ")");
  1359. }
  1360. }
  1361. static void copyFile(File srcFile, File dstFile)
  1362. throws IOException
  1363. {
  1364. // FIXME should really be using commons io FileUtils here, but don't want
  1365. // to add dep for one simple test method
  1366. byte[] buf = new byte[1024];
  1367. OutputStream ostream = new FileOutputStream(dstFile);
  1368. InputStream istream = new FileInputStream(srcFile);
  1369. try {
  1370. int numBytes = 0;
  1371. while((numBytes = istream.read(buf)) >= 0) {
  1372. ostream.write(buf, 0, numBytes);
  1373. }
  1374. } finally {
  1375. ostream.close();
  1376. }
  1377. }
  1378. static File createTempFile(boolean keep) throws Exception {
  1379. File tmp = File.createTempFile("databaseTest", ".mdb");
  1380. if(keep) {
  1381. System.out.println("Created " + tmp);
  1382. } else {
  1383. tmp.deleteOnExit();
  1384. }
  1385. return tmp;
  1386. }
  1387. public static byte[] toByteArray(File file)
  1388. throws IOException
  1389. {
  1390. // FIXME should really be using commons io IOUtils here, but don't want
  1391. // to add dep for one simple test method
  1392. FileInputStream istream = new FileInputStream(file);
  1393. try {
  1394. byte[] bytes = new byte[(int)file.length()];
  1395. istream.read(bytes);
  1396. return bytes;
  1397. } finally {
  1398. istream.close();
  1399. }
  1400. }
  1401. }