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.

IndexTest.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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.IOException;
  15. import java.util.ArrayList;
  16. import java.util.Arrays;
  17. import java.util.HashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.SortedSet;
  21. import java.util.TreeSet;
  22. import static com.healthmarketscience.jackcess.Database.*;
  23. import com.healthmarketscience.jackcess.impl.ByteUtil;
  24. import com.healthmarketscience.jackcess.impl.IndexCodesTest;
  25. import com.healthmarketscience.jackcess.impl.IndexData;
  26. import com.healthmarketscience.jackcess.impl.IndexImpl;
  27. import static com.healthmarketscience.jackcess.impl.JetFormatTest.*;
  28. import com.healthmarketscience.jackcess.impl.RowIdImpl;
  29. import com.healthmarketscience.jackcess.impl.TableImpl;
  30. import junit.framework.TestCase;
  31. import static com.healthmarketscience.jackcess.TestUtil.*;
  32. import static com.healthmarketscience.jackcess.DatabaseBuilder.*;
  33. /**
  34. * @author James Ahlborn
  35. */
  36. public class IndexTest extends TestCase {
  37. public IndexTest(String name) {
  38. super(name);
  39. }
  40. @Override
  41. protected void setUp() {
  42. TestUtil.setTestAutoSync(false);
  43. }
  44. @Override
  45. protected void tearDown() {
  46. TestUtil.clearTestAutoSync();
  47. }
  48. public void testByteOrder() throws Exception {
  49. byte b1 = (byte)0x00;
  50. byte b2 = (byte)0x01;
  51. byte b3 = (byte)0x7F;
  52. byte b4 = (byte)0x80;
  53. byte b5 = (byte)0xFF;
  54. assertTrue(ByteUtil.asUnsignedByte(b1) < ByteUtil.asUnsignedByte(b2));
  55. assertTrue(ByteUtil.asUnsignedByte(b2) < ByteUtil.asUnsignedByte(b3));
  56. assertTrue(ByteUtil.asUnsignedByte(b3) < ByteUtil.asUnsignedByte(b4));
  57. assertTrue(ByteUtil.asUnsignedByte(b4) < ByteUtil.asUnsignedByte(b5));
  58. }
  59. public void testByteCodeComparator() {
  60. byte[] b0 = null;
  61. byte[] b1 = new byte[]{(byte)0x00};
  62. byte[] b2 = new byte[]{(byte)0x00, (byte)0x00};
  63. byte[] b3 = new byte[]{(byte)0x00, (byte)0x01};
  64. byte[] b4 = new byte[]{(byte)0x01};
  65. byte[] b5 = new byte[]{(byte)0x80};
  66. byte[] b6 = new byte[]{(byte)0xFF};
  67. byte[] b7 = new byte[]{(byte)0xFF, (byte)0x00};
  68. byte[] b8 = new byte[]{(byte)0xFF, (byte)0x01};
  69. List<byte[]> expectedList = Arrays.<byte[]>asList(b0, b1, b2, b3, b4,
  70. b5, b6, b7, b8);
  71. SortedSet<byte[]> sortedSet = new TreeSet<byte[]>(
  72. IndexData.BYTE_CODE_COMPARATOR);
  73. sortedSet.addAll(expectedList);
  74. assertEquals(expectedList, new ArrayList<byte[]>(sortedSet));
  75. }
  76. public void testPrimaryKey() throws Exception {
  77. for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
  78. Table table = open(testDB).getTable("Table1");
  79. Map<String, Boolean> foundPKs = new HashMap<String, Boolean>();
  80. Index pkIndex = null;
  81. for(Index index : table.getIndexes()) {
  82. foundPKs.put(index.getColumns().iterator().next().getName(),
  83. index.isPrimaryKey());
  84. if(index.isPrimaryKey()) {
  85. pkIndex= index;
  86. }
  87. }
  88. Map<String, Boolean> expectedPKs = new HashMap<String, Boolean>();
  89. expectedPKs.put("A", Boolean.TRUE);
  90. expectedPKs.put("B", Boolean.FALSE);
  91. assertEquals(expectedPKs, foundPKs);
  92. assertSame(pkIndex, table.getPrimaryKeyIndex());
  93. }
  94. }
  95. public void testLogicalIndexes() throws Exception
  96. {
  97. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX, true)) {
  98. Database mdb = open(testDB);
  99. TableImpl table = (TableImpl)mdb.getTable("Table1");
  100. for(IndexImpl idx : table.getIndexes()) {
  101. idx.initialize();
  102. }
  103. assertEquals(4, table.getIndexes().size());
  104. assertEquals(4, table.getLogicalIndexCount());
  105. checkIndexColumns(table,
  106. "id", "id",
  107. "PrimaryKey", "id",
  108. "Table2Table1", "otherfk1",
  109. "Table3Table1", "otherfk2");
  110. table = (TableImpl)mdb.getTable("Table2");
  111. for(IndexImpl idx : table.getIndexes()) {
  112. idx.initialize();
  113. }
  114. assertEquals(3, table.getIndexes().size());
  115. assertEquals(2, table.getIndexDatas().size());
  116. assertEquals(3, table.getLogicalIndexCount());
  117. checkIndexColumns(table,
  118. "id", "id",
  119. "PrimaryKey", "id",
  120. ".rC", "id");
  121. IndexImpl pkIdx = table.getIndex("PrimaryKey");
  122. IndexImpl fkIdx = table.getIndex(".rC");
  123. assertNotSame(pkIdx, fkIdx);
  124. assertTrue(fkIdx.isForeignKey());
  125. assertSame(pkIdx.getIndexData(), fkIdx.getIndexData());
  126. IndexData indexData = pkIdx.getIndexData();
  127. assertEquals(Arrays.asList(pkIdx, fkIdx), indexData.getIndexes());
  128. assertSame(pkIdx, indexData.getPrimaryIndex());
  129. table = (TableImpl)mdb.getTable("Table3");
  130. for(IndexImpl idx : table.getIndexes()) {
  131. idx.initialize();
  132. }
  133. assertEquals(3, table.getIndexes().size());
  134. assertEquals(2, table.getIndexDatas().size());
  135. assertEquals(3, table.getLogicalIndexCount());
  136. checkIndexColumns(table,
  137. "id", "id",
  138. "PrimaryKey", "id",
  139. ".rC", "id");
  140. pkIdx = table.getIndex("PrimaryKey");
  141. fkIdx = table.getIndex(".rC");
  142. assertNotSame(pkIdx, fkIdx);
  143. assertTrue(fkIdx.isForeignKey());
  144. assertSame(pkIdx.getIndexData(), fkIdx.getIndexData());
  145. indexData = pkIdx.getIndexData();
  146. assertEquals(Arrays.asList(pkIdx, fkIdx), indexData.getIndexes());
  147. assertSame(pkIdx, indexData.getPrimaryIndex());
  148. }
  149. }
  150. public void testComplexIndex() throws Exception
  151. {
  152. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.COMP_INDEX)) {
  153. // this file has an index with "compressed" entries and node pages
  154. Database db = open(testDB);
  155. TableImpl t = (TableImpl)db.getTable("Table1");
  156. IndexImpl index = t.getIndexes().get(0);
  157. assertFalse(index.isInitialized());
  158. assertEquals(512, countRows(t));
  159. assertEquals(512, index.getIndexData().getEntryCount());
  160. db.close();
  161. // copy to temp file and attempt to edit
  162. db = openCopy(testDB);
  163. t = (TableImpl)db.getTable("Table1");
  164. index = t.getIndexes().get(0);
  165. t.addRow(99, "abc", "def");
  166. }
  167. }
  168. public void testEntryDeletion() throws Exception {
  169. for (final TestDB testDB : SUPPORTED_DBS_TEST) {
  170. Table table = openCopy(testDB).getTable("Table1");
  171. for(int i = 0; i < 10; ++i) {
  172. table.addRow("foo" + i, "bar" + i, (byte)42 + i, (short)53 + i, 13 * i,
  173. (6.7d / i), null, null, true);
  174. }
  175. table.reset();
  176. assertRowCount(12, table);
  177. for(Index index : table.getIndexes()) {
  178. assertEquals(12, ((IndexImpl)index).getIndexData().getEntryCount());
  179. }
  180. table.reset();
  181. table.getNextRow();
  182. table.getNextRow();
  183. table.getDefaultCursor().deleteCurrentRow();
  184. table.getNextRow();
  185. table.getDefaultCursor().deleteCurrentRow();
  186. table.getNextRow();
  187. table.getNextRow();
  188. table.getDefaultCursor().deleteCurrentRow();
  189. table.getNextRow();
  190. table.getNextRow();
  191. table.getNextRow();
  192. table.getDefaultCursor().deleteCurrentRow();
  193. table.reset();
  194. assertRowCount(8, table);
  195. for(Index index : table.getIndexes()) {
  196. assertEquals(8, ((IndexImpl)index).getIndexData().getEntryCount());
  197. }
  198. }
  199. }
  200. public void testIgnoreNulls() throws Exception
  201. {
  202. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX_PROPERTIES)) {
  203. Database db = openCopy(testDB);
  204. db.setEvaluateExpressions(false);
  205. doTestIgnoreNulls(db, "TableIgnoreNulls1");
  206. doTestIgnoreNulls(db, "TableIgnoreNulls2");
  207. db.close();
  208. }
  209. }
  210. private void doTestIgnoreNulls(Database db, String tableName)
  211. throws Exception
  212. {
  213. Table orig = db.getTable(tableName);
  214. IndexImpl origI = (IndexImpl)orig.getIndex("DataIndex");
  215. Table temp = db.getTable(tableName + "_temp");
  216. IndexImpl tempI = (IndexImpl)temp.getIndex("DataIndex");
  217. // copy from orig table to temp table
  218. for(Map<String,Object> row : orig) {
  219. temp.addRow(orig.asRow(row));
  220. }
  221. assertEquals(origI.getIndexData().getEntryCount(),
  222. tempI.getIndexData().getEntryCount());
  223. Cursor origC = origI.newCursor().toCursor();
  224. Cursor tempC = tempI.newCursor().toCursor();
  225. while(true) {
  226. boolean origHasNext = origC.moveToNextRow();
  227. boolean tempHasNext = tempC.moveToNextRow();
  228. assertTrue(origHasNext == tempHasNext);
  229. if(!origHasNext) {
  230. break;
  231. }
  232. Map<String,Object> origRow = origC.getCurrentRow();
  233. Cursor.Position origCurPos = origC.getSavepoint().getCurrentPosition();
  234. Map<String,Object> tempRow = tempC.getCurrentRow();
  235. Cursor.Position tempCurPos = tempC.getSavepoint().getCurrentPosition();
  236. assertEquals(origRow, tempRow);
  237. assertEquals(IndexCodesTest.entryToString(origCurPos),
  238. IndexCodesTest.entryToString(tempCurPos));
  239. }
  240. }
  241. public void testUnique() throws Exception
  242. {
  243. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX_PROPERTIES)) {
  244. Database db = openCopy(testDB);
  245. Table t = db.getTable("TableUnique1_temp");
  246. Index index = t.getIndex("DataIndex");
  247. doTestUnique(index, 1,
  248. null, true,
  249. "unique data", true,
  250. null, true,
  251. "more", false,
  252. "stuff", false,
  253. "unique data", false);
  254. t = db.getTable("TableUnique2_temp");
  255. index = t.getIndex("DataIndex");
  256. doTestUnique(index, 2,
  257. null, null, true,
  258. "unique data", 42, true,
  259. "unique data", null, true,
  260. null, null, true,
  261. "some", 42, true,
  262. "more unique data", 13, true,
  263. null, -4242, true,
  264. "another row", -3462, false,
  265. null, 49, false,
  266. "more", null, false,
  267. "unique data", 42, false,
  268. "unique data", null, false,
  269. null, -4242, false);
  270. db.close();
  271. }
  272. }
  273. private void doTestUnique(Index index, int numValues,
  274. Object... testData)
  275. throws Exception
  276. {
  277. for(int i = 0; i < testData.length; i += (numValues + 1)) {
  278. Object[] row = new Object[numValues + 1];
  279. row[0] = "testRow" + i;
  280. for(int j = 1; j < (numValues + 1); ++j) {
  281. row[j] = testData[i + j - 1];
  282. }
  283. boolean expectedSuccess = (Boolean)testData[i + numValues];
  284. IOException failure = null;
  285. try {
  286. ((IndexImpl)index).getIndexData().prepareAddRow(
  287. row, new RowIdImpl(400 + i, 0), null).commit();
  288. } catch(IOException e) {
  289. failure = e;
  290. }
  291. if(expectedSuccess) {
  292. assertNull(failure);
  293. } else {
  294. assertTrue(failure != null);
  295. assertTrue(failure.getMessage().contains("uniqueness"));
  296. }
  297. }
  298. }
  299. public void testUniqueEntryCount() throws Exception {
  300. for (final TestDB testDB : SUPPORTED_DBS_TEST) {
  301. Database db = openCopy(testDB);
  302. db.setDateTimeType(DateTimeType.DATE);
  303. Table table = db.getTable("Table1");
  304. IndexImpl indA = (IndexImpl)table.getIndex("PrimaryKey");
  305. IndexImpl indB = (IndexImpl)table.getIndex("B");
  306. assertEquals(2, indA.getUniqueEntryCount());
  307. assertEquals(2, indB.getUniqueEntryCount());
  308. List<String> bElems = Arrays.asList("bar", null, "baz", "argle", null,
  309. "bazzle", "37", "bar", "bar", "BAZ");
  310. for(int i = 0; i < 10; ++i) {
  311. table.addRow("foo" + i, bElems.get(i), (byte)42 + i, (short)53 + i,
  312. 13 * i, (6.7d / i), null, null, true);
  313. }
  314. assertEquals(12, indA.getIndexData().getEntryCount());
  315. assertEquals(12, indB.getIndexData().getEntryCount());
  316. assertEquals(12, indA.getUniqueEntryCount());
  317. assertEquals(8, indB.getUniqueEntryCount());
  318. table = null;
  319. indA = null;
  320. indB = null;
  321. table = db.getTable("Table1");
  322. indA = (IndexImpl)table.getIndex("PrimaryKey");
  323. indB = (IndexImpl)table.getIndex("B");
  324. assertEquals(12, indA.getIndexData().getEntryCount());
  325. assertEquals(12, indB.getIndexData().getEntryCount());
  326. assertEquals(12, indA.getUniqueEntryCount());
  327. assertEquals(8, indB.getUniqueEntryCount());
  328. Cursor c = CursorBuilder.createCursor(table);
  329. assertTrue(c.moveToNextRow());
  330. final Row row = c.getCurrentRow();
  331. // Row order is arbitrary, so v2007 row order difference is valid
  332. if (testDB.getExpectedFileFormat().ordinal() >=
  333. Database.FileFormat.V2007.ordinal()) {
  334. TestUtil.checkTestDBTable1RowA(testDB, table, row);
  335. } else {
  336. TestUtil.checkTestDBTable1RowABCDEFG(testDB, table, row);
  337. }
  338. c.deleteCurrentRow();
  339. assertEquals(11, indA.getIndexData().getEntryCount());
  340. assertEquals(11, indB.getIndexData().getEntryCount());
  341. assertEquals(12, indA.getUniqueEntryCount());
  342. assertEquals(8, indB.getUniqueEntryCount());
  343. db.close();
  344. }
  345. }
  346. public void testReplId() throws Exception
  347. {
  348. for (final TestDB testDB : SUPPORTED_DBS_TEST) {
  349. Database db = openCopy(testDB);
  350. Table table = db.getTable("Table4");
  351. for(int i = 0; i< 20; ++i) {
  352. table.addRow("row" + i, Column.AUTO_NUMBER);
  353. }
  354. assertEquals(20, table.getRowCount());
  355. db.close();
  356. }
  357. }
  358. public void testIndexCreation() throws Exception
  359. {
  360. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  361. Database db = create(fileFormat);
  362. Table t = newTable("TestTable")
  363. .addColumn(newColumn("id", DataType.LONG))
  364. .addColumn(newColumn("data", DataType.TEXT))
  365. .setPrimaryKey("id")
  366. .toTable(db);
  367. assertEquals(1, t.getIndexes().size());
  368. IndexImpl idx = (IndexImpl)t.getIndexes().get(0);
  369. assertEquals(IndexBuilder.PRIMARY_KEY_NAME, idx.getName());
  370. assertEquals(1, idx.getColumns().size());
  371. assertEquals("id", idx.getColumns().get(0).getName());
  372. assertTrue(idx.getColumns().get(0).isAscending());
  373. assertTrue(idx.isPrimaryKey());
  374. assertTrue(idx.isUnique());
  375. assertFalse(idx.shouldIgnoreNulls());
  376. assertNull(idx.getReference());
  377. t.addRow(2, "row2");
  378. t.addRow(1, "row1");
  379. t.addRow(3, "row3");
  380. Cursor c = t.newCursor()
  381. .setIndexByName(IndexBuilder.PRIMARY_KEY_NAME).toCursor();
  382. for(int i = 1; i <= 3; ++i) {
  383. Map<String,Object> row = c.getNextRow();
  384. assertEquals(i, row.get("id"));
  385. assertEquals("row" + i, row.get("data"));
  386. }
  387. assertFalse(c.moveToNextRow());
  388. }
  389. }
  390. public void testIndexCreationSharedData() throws Exception
  391. {
  392. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  393. Database db = create(fileFormat);
  394. Table t = newTable("TestTable")
  395. .addColumn(newColumn("id", DataType.LONG))
  396. .addColumn(newColumn("data", DataType.TEXT))
  397. .setPrimaryKey("id")
  398. .addIndex(newIndex("Index1").addColumns("id"))
  399. .addIndex(newIndex("Index2").addColumns("id"))
  400. .addIndex(newIndex("Index3").addColumns(false, "id"))
  401. .toTable(db);
  402. assertEquals(4, t.getIndexes().size());
  403. IndexImpl idx = (IndexImpl)t.getIndexes().get(0);
  404. assertEquals(IndexBuilder.PRIMARY_KEY_NAME, idx.getName());
  405. assertEquals(1, idx.getColumns().size());
  406. assertEquals("id", idx.getColumns().get(0).getName());
  407. assertTrue(idx.getColumns().get(0).isAscending());
  408. assertTrue(idx.isPrimaryKey());
  409. assertTrue(idx.isUnique());
  410. assertFalse(idx.shouldIgnoreNulls());
  411. assertNull(idx.getReference());
  412. IndexImpl idx1 = (IndexImpl)t.getIndexes().get(1);
  413. IndexImpl idx2 = (IndexImpl)t.getIndexes().get(2);
  414. IndexImpl idx3 = (IndexImpl)t.getIndexes().get(3);
  415. assertNotSame(idx.getIndexData(), idx1.getIndexData());
  416. assertSame(idx1.getIndexData(), idx2.getIndexData());
  417. assertNotSame(idx2.getIndexData(), idx3.getIndexData());
  418. t.addRow(2, "row2");
  419. t.addRow(1, "row1");
  420. t.addRow(3, "row3");
  421. Cursor c = t.newCursor()
  422. .setIndexByName(IndexBuilder.PRIMARY_KEY_NAME).toCursor();
  423. for(int i = 1; i <= 3; ++i) {
  424. Map<String,Object> row = c.getNextRow();
  425. assertEquals(i, row.get("id"));
  426. assertEquals("row" + i, row.get("data"));
  427. }
  428. assertFalse(c.moveToNextRow());
  429. }
  430. }
  431. public void testGetForeignKeyIndex() throws Exception
  432. {
  433. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX, true)) {
  434. Database db = open(testDB);
  435. Table t1 = db.getTable("Table1");
  436. Table t2 = db.getTable("Table2");
  437. Table t3 = db.getTable("Table3");
  438. IndexImpl t2t1 = (IndexImpl)t1.getIndex("Table2Table1");
  439. IndexImpl t3t1 = (IndexImpl)t1.getIndex("Table3Table1");
  440. assertTrue(t2t1.isForeignKey());
  441. assertNotNull(t2t1.getReference());
  442. assertFalse(t2t1.getReference().isPrimaryTable());
  443. assertFalse(t2t1.getReference().isCascadeUpdates());
  444. assertTrue(t2t1.getReference().isCascadeDeletes());
  445. doCheckForeignKeyIndex(t1, t2t1, t2);
  446. assertTrue(t3t1.isForeignKey());
  447. assertNotNull(t3t1.getReference());
  448. assertFalse(t3t1.getReference().isPrimaryTable());
  449. assertTrue(t3t1.getReference().isCascadeUpdates());
  450. assertFalse(t3t1.getReference().isCascadeDeletes());
  451. doCheckForeignKeyIndex(t1, t3t1, t3);
  452. Index t1pk = t1.getIndex(IndexBuilder.PRIMARY_KEY_NAME);
  453. assertNotNull(t1pk);
  454. assertNull(((IndexImpl)t1pk).getReference());
  455. assertNull(t1pk.getReferencedIndex());
  456. }
  457. }
  458. public void testConstraintViolation() throws Exception
  459. {
  460. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  461. Database db = create(fileFormat);
  462. Table t = newTable("TestTable")
  463. .addColumn(newColumn("id", DataType.LONG))
  464. .addColumn(newColumn("data", DataType.TEXT))
  465. .setPrimaryKey("id")
  466. .addIndex(newIndex("data_ind")
  467. .addColumns("data").setUnique())
  468. .toTable(db);
  469. for(int i = 0; i < 5; ++i) {
  470. t.addRow(i, "row" + i);
  471. }
  472. try {
  473. t.addRow(3, "badrow");
  474. fail("ConstraintViolationException should have been thrown");
  475. } catch(ConstraintViolationException ce) {
  476. // success
  477. }
  478. assertEquals(5, t.getRowCount());
  479. List<Row> expectedRows =
  480. createExpectedTable(
  481. createExpectedRow(
  482. "id", 0, "data", "row0"),
  483. createExpectedRow(
  484. "id", 1, "data", "row1"),
  485. createExpectedRow(
  486. "id", 2, "data", "row2"),
  487. createExpectedRow(
  488. "id", 3, "data", "row3"),
  489. createExpectedRow(
  490. "id", 4, "data", "row4"));
  491. assertTable(expectedRows, t);
  492. IndexCursor pkCursor = CursorBuilder.createPrimaryKeyCursor(t);
  493. assertCursor(expectedRows, pkCursor);
  494. assertCursor(expectedRows,
  495. CursorBuilder.createCursor(t.getIndex("data_ind")));
  496. List<Object[]> batch = new ArrayList<Object[]>();
  497. batch.add(new Object[]{5, "row5"});
  498. batch.add(new Object[]{6, "row6"});
  499. batch.add(new Object[]{7, "row2"});
  500. batch.add(new Object[]{8, "row8"});
  501. try {
  502. t.addRows(batch);
  503. fail("BatchUpdateException should have been thrown");
  504. } catch(BatchUpdateException be) {
  505. // success
  506. assertTrue(be.getCause() instanceof ConstraintViolationException);
  507. assertEquals(2, be.getUpdateCount());
  508. }
  509. expectedRows = new ArrayList<Row>(expectedRows);
  510. expectedRows.add(createExpectedRow("id", 5, "data", "row5"));
  511. expectedRows.add(createExpectedRow("id", 6, "data", "row6"));
  512. assertTable(expectedRows, t);
  513. assertCursor(expectedRows, pkCursor);
  514. assertCursor(expectedRows,
  515. CursorBuilder.createCursor(t.getIndex("data_ind")));
  516. pkCursor.findFirstRowByEntry(4);
  517. Row row4 = pkCursor.getCurrentRow();
  518. row4.put("id", 3);
  519. try {
  520. t.updateRow(row4);
  521. fail("ConstraintViolationException should have been thrown");
  522. } catch(ConstraintViolationException ce) {
  523. // success
  524. }
  525. assertTable(expectedRows, t);
  526. assertCursor(expectedRows, pkCursor);
  527. assertCursor(expectedRows,
  528. CursorBuilder.createCursor(t.getIndex("data_ind")));
  529. db.close();
  530. }
  531. }
  532. public void testAutoNumberRecover() throws Exception
  533. {
  534. for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
  535. Database db = create(fileFormat);
  536. Table t = newTable("TestTable")
  537. .addColumn(newColumn("id", DataType.LONG).setAutoNumber(true))
  538. .addColumn(newColumn("data", DataType.TEXT))
  539. .setPrimaryKey("id")
  540. .addIndex(newIndex("data_ind")
  541. .addColumns("data").setUnique())
  542. .toTable(db);
  543. for(int i = 1; i < 3; ++i) {
  544. t.addRow(null, "row" + i);
  545. }
  546. try {
  547. t.addRow(null, "row1");
  548. fail("ConstraintViolationException should have been thrown");
  549. } catch(ConstraintViolationException ce) {
  550. // success
  551. }
  552. t.addRow(null, "row3");
  553. assertEquals(3, t.getRowCount());
  554. List<Row> expectedRows =
  555. createExpectedTable(
  556. createExpectedRow(
  557. "id", 1, "data", "row1"),
  558. createExpectedRow(
  559. "id", 2, "data", "row2"),
  560. createExpectedRow(
  561. "id", 3, "data", "row3"));
  562. assertTable(expectedRows, t);
  563. IndexCursor pkCursor = CursorBuilder.createPrimaryKeyCursor(t);
  564. assertCursor(expectedRows, pkCursor);
  565. assertCursor(expectedRows,
  566. CursorBuilder.createCursor(t.getIndex("data_ind")));
  567. List<Object[]> batch = new ArrayList<Object[]>();
  568. batch.add(new Object[]{null, "row4"});
  569. batch.add(new Object[]{null, "row5"});
  570. batch.add(new Object[]{null, "row3"});
  571. try {
  572. t.addRows(batch);
  573. fail("BatchUpdateException should have been thrown");
  574. } catch(BatchUpdateException be) {
  575. // success
  576. assertTrue(be.getCause() instanceof ConstraintViolationException);
  577. assertEquals(2, be.getUpdateCount());
  578. }
  579. expectedRows = new ArrayList<Row>(expectedRows);
  580. expectedRows.add(createExpectedRow("id", 4, "data", "row4"));
  581. expectedRows.add(createExpectedRow("id", 5, "data", "row5"));
  582. assertTable(expectedRows, t);
  583. assertCursor(expectedRows, pkCursor);
  584. assertCursor(expectedRows,
  585. CursorBuilder.createCursor(t.getIndex("data_ind")));
  586. db.close();
  587. }
  588. }
  589. public void testBinaryIndex() throws Exception
  590. {
  591. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.BINARY_INDEX)) {
  592. Database db = open(testDB);
  593. Table table = db.getTable("Test");
  594. Index idx = table.getIndex("BinAscIdx");
  595. doTestBinaryIndex(idx, "BinAsc", false);
  596. idx = table.getIndex("BinDscIdx");
  597. doTestBinaryIndex(idx, "BinDsc", true);
  598. db.close();
  599. }
  600. }
  601. private static void doTestBinaryIndex(Index idx, String colName, boolean forward)
  602. throws Exception
  603. {
  604. IndexCursor ic = CursorBuilder.createCursor(idx);
  605. for(Row row : idx.getTable().getDefaultCursor().newIterable().setForward(forward)) {
  606. int id = row.getInt("ID");
  607. byte[] data = row.getBytes(colName);
  608. boolean found = false;
  609. for(Row idxRow : ic.newEntryIterable(data)) {
  610. assertTrue(Arrays.equals(data, idxRow.getBytes(colName)));
  611. if(id == idxRow.getInt("ID")) {
  612. found = true;
  613. }
  614. }
  615. assertTrue(found);
  616. }
  617. }
  618. private void doCheckForeignKeyIndex(Table ta, Index ia, Table tb)
  619. throws Exception
  620. {
  621. IndexImpl ib = (IndexImpl)ia.getReferencedIndex();
  622. assertNotNull(ib);
  623. assertSame(tb, ib.getTable());
  624. assertNotNull(ib.getReference());
  625. assertSame(ia, ib.getReferencedIndex());
  626. assertTrue(ib.getReference().isPrimaryTable());
  627. }
  628. private void checkIndexColumns(Table table, String... idxInfo)
  629. throws Exception
  630. {
  631. Map<String, String> expectedIndexes = new HashMap<String, String>();
  632. for(int i = 0; i < idxInfo.length; i+=2) {
  633. expectedIndexes.put(idxInfo[i], idxInfo[i+1]);
  634. }
  635. for(Index idx : table.getIndexes()) {
  636. String colName = expectedIndexes.get(idx.getName());
  637. assertEquals(1, idx.getColumns().size());
  638. assertEquals(colName, idx.getColumns().get(0).getName());
  639. if("PrimaryKey".equals(idx.getName())) {
  640. assertTrue(idx.isPrimaryKey());
  641. } else {
  642. assertFalse(idx.isPrimaryKey());
  643. }
  644. }
  645. }
  646. }