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.

CursorTest.java 50KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596
  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.util.ArrayList;
  15. import java.util.Arrays;
  16. import java.util.Collections;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.NoSuchElementException;
  21. import java.util.TreeSet;
  22. import java.util.stream.Collectors;
  23. import static com.healthmarketscience.jackcess.Database.*;
  24. import com.healthmarketscience.jackcess.impl.ColumnImpl;
  25. import com.healthmarketscience.jackcess.impl.JetFormatTest;
  26. import static com.healthmarketscience.jackcess.impl.JetFormatTest.*;
  27. import com.healthmarketscience.jackcess.impl.RowIdImpl;
  28. import com.healthmarketscience.jackcess.impl.TableImpl;
  29. import com.healthmarketscience.jackcess.util.CaseInsensitiveColumnMatcher;
  30. import com.healthmarketscience.jackcess.util.ColumnMatcher;
  31. import com.healthmarketscience.jackcess.util.RowFilterTest;
  32. import com.healthmarketscience.jackcess.util.SimpleColumnMatcher;
  33. import static com.healthmarketscience.jackcess.TestUtil.*;
  34. import static com.healthmarketscience.jackcess.DatabaseBuilder.*;
  35. import org.junit.jupiter.api.AfterEach;
  36. import static org.junit.jupiter.api.Assertions.*;
  37. import org.junit.jupiter.api.BeforeEach;
  38. import org.junit.jupiter.api.Test;
  39. /**
  40. * @author James Ahlborn
  41. */
  42. public class CursorTest
  43. {
  44. static final List<TestDB> INDEX_CURSOR_DBS =
  45. TestDB.getSupportedForBasename(Basename.INDEX_CURSOR);
  46. @BeforeEach
  47. protected void setUp() {
  48. TestUtil.setTestAutoSync(false);
  49. }
  50. @AfterEach
  51. protected void tearDown() {
  52. TestUtil.clearTestAutoSync();
  53. }
  54. private static List<Map<String,Object>> createTestTableData()
  55. throws Exception
  56. {
  57. List<Map<String,Object>> expectedRows =
  58. new ArrayList<Map<String,Object>>();
  59. for(int i = 0; i < 10; ++i) {
  60. expectedRows.add(createExpectedRow("id", i, "value", "data" + i));
  61. }
  62. return expectedRows;
  63. }
  64. private static List<Map<String,Object>> createTestTableData(
  65. int startIdx,
  66. int endIdx)
  67. throws Exception
  68. {
  69. List<Map<String,Object>> expectedRows = createTestTableData();
  70. expectedRows.subList(endIdx, expectedRows.size()).clear();
  71. expectedRows.subList(0, startIdx).clear();
  72. return expectedRows;
  73. }
  74. private static Database createTestTable(final FileFormat fileFormat)
  75. throws Exception
  76. {
  77. Database db = createMem(fileFormat);
  78. Table table = newTable("test")
  79. .addColumn(newColumn("id", DataType.LONG))
  80. .addColumn(newColumn("value", DataType.TEXT))
  81. .toTable(db);
  82. for(Map<String,Object> row : createTestTableData()) {
  83. table.addRow(row.get("id"), row.get("value"));
  84. }
  85. return db;
  86. }
  87. private static List<Map<String,Object>> createUnorderedTestTableData()
  88. throws Exception
  89. {
  90. List<Map<String,Object>> expectedRows =
  91. new ArrayList<Map<String,Object>>();
  92. int[] ids = new int[]{3, 7, 6, 1, 2, 9, 0, 5, 4, 8};
  93. for(int i : ids) {
  94. expectedRows.add(createExpectedRow("id", i, "value", "data" + i));
  95. }
  96. return expectedRows;
  97. }
  98. static Database createTestIndexTable(final TestDB indexCursorDB)
  99. throws Exception
  100. {
  101. Database db = openMem(indexCursorDB);
  102. Table table = db.getTable("test");
  103. for(Map<String,Object> row : createUnorderedTestTableData()) {
  104. table.addRow(row.get("id"), row.get("value"));
  105. }
  106. return db;
  107. }
  108. private static List<Map<String,Object>> createDupeTestTableData()
  109. throws Exception
  110. {
  111. List<Map<String,Object>> expectedRows =
  112. new ArrayList<Map<String,Object>>();
  113. int[] ids = new int[]{3, 7, 6, 1, 2, 9, 0, 5, 4, 8};
  114. for(int i : ids) {
  115. expectedRows.add(createExpectedRow("id", i, "value", "data" + (i % 3)));
  116. }
  117. for(int i : ids) {
  118. expectedRows.add(createExpectedRow("id", i, "value", "data" + (i % 5)));
  119. }
  120. return expectedRows;
  121. }
  122. private static Database createDupeTestTable(final FileFormat fileFormat)
  123. throws Exception
  124. {
  125. Database db = createMem(fileFormat);
  126. Table table = newTable("test")
  127. .addColumn(newColumn("id", DataType.LONG))
  128. .addColumn(newColumn("value", DataType.TEXT))
  129. .toTable(db);
  130. for(Map<String,Object> row : createDupeTestTableData()) {
  131. table.addRow(row.get("id"), row.get("value"));
  132. }
  133. return db;
  134. }
  135. static Database createDupeTestTable(final TestDB indexCursorDB)
  136. throws Exception
  137. {
  138. Database db = openMem(indexCursorDB);
  139. Table table = db.getTable("test");
  140. for(Map<String,Object> row : createDupeTestTableData()) {
  141. table.addRow(row.get("id"), row.get("value"));
  142. }
  143. return db;
  144. }
  145. private static Cursor createIndexSubRangeCursor(Table table,
  146. Index idx,
  147. int type)
  148. throws Exception
  149. {
  150. return table.newCursor()
  151. .setIndex(idx)
  152. .setStartEntry(3 - type)
  153. .setStartRowInclusive(type == 0)
  154. .setEndEntry(8 + type)
  155. .setEndRowInclusive(type == 0)
  156. .toCursor();
  157. }
  158. @Test
  159. public void testRowId() throws Exception {
  160. // test special cases
  161. RowIdImpl rowId1 = new RowIdImpl(1, 2);
  162. RowIdImpl rowId2 = new RowIdImpl(1, 3);
  163. RowIdImpl rowId3 = new RowIdImpl(2, 1);
  164. List<RowIdImpl> sortedRowIds =
  165. new ArrayList<RowIdImpl>(new TreeSet<RowIdImpl>(
  166. Arrays.asList(rowId1, rowId2, rowId3, RowIdImpl.FIRST_ROW_ID,
  167. RowIdImpl.LAST_ROW_ID)));
  168. assertEquals(Arrays.asList(RowIdImpl.FIRST_ROW_ID, rowId1, rowId2, rowId3,
  169. RowIdImpl.LAST_ROW_ID),
  170. sortedRowIds);
  171. }
  172. @Test
  173. public void testSimple() throws Exception {
  174. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  175. Database db = createTestTable(fileFormat);
  176. Table table = db.getTable("test");
  177. Cursor cursor = CursorBuilder.createCursor(table);
  178. doTestSimple(cursor, null);
  179. db.close();
  180. }
  181. }
  182. private static void doTestSimple(Cursor cursor,
  183. List<Map<String, Object>> expectedRows)
  184. throws Exception
  185. {
  186. if(expectedRows == null) {
  187. expectedRows = createTestTableData();
  188. }
  189. List<Map<String, Object>> foundRows =
  190. new ArrayList<Map<String, Object>>();
  191. for(Map<String, Object> row : cursor) {
  192. foundRows.add(row);
  193. }
  194. assertEquals(expectedRows, foundRows);
  195. }
  196. @Test
  197. public void testMove() throws Exception {
  198. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  199. Database db = createTestTable(fileFormat);
  200. Table table = db.getTable("test");
  201. Cursor cursor = CursorBuilder.createCursor(table);
  202. doTestMove(cursor, null);
  203. db.close();
  204. }
  205. }
  206. private static void doTestMove(Cursor cursor,
  207. List<Map<String, Object>> expectedRows)
  208. throws Exception
  209. {
  210. if(expectedRows == null) {
  211. expectedRows = createTestTableData();
  212. }
  213. expectedRows.subList(1, 4).clear();
  214. List<Map<String, Object>> foundRows =
  215. new ArrayList<Map<String, Object>>();
  216. assertTrue(cursor.isBeforeFirst());
  217. assertFalse(cursor.isAfterLast());
  218. foundRows.add(cursor.getNextRow());
  219. assertEquals(3, cursor.moveNextRows(3));
  220. assertFalse(cursor.isBeforeFirst());
  221. assertFalse(cursor.isAfterLast());
  222. Map<String,Object> expectedRow = cursor.getCurrentRow();
  223. Cursor.Savepoint savepoint = cursor.getSavepoint();
  224. assertEquals(2, cursor.movePreviousRows(2));
  225. assertEquals(2, cursor.moveNextRows(2));
  226. assertTrue(cursor.moveToNextRow());
  227. assertTrue(cursor.moveToPreviousRow());
  228. assertEquals(expectedRow, cursor.getCurrentRow());
  229. while(cursor.moveToNextRow()) {
  230. foundRows.add(cursor.getCurrentRow());
  231. }
  232. assertEquals(expectedRows, foundRows);
  233. assertFalse(cursor.isBeforeFirst());
  234. assertTrue(cursor.isAfterLast());
  235. assertEquals(0, cursor.moveNextRows(3));
  236. cursor.beforeFirst();
  237. assertTrue(cursor.isBeforeFirst());
  238. assertFalse(cursor.isAfterLast());
  239. cursor.afterLast();
  240. assertFalse(cursor.isBeforeFirst());
  241. assertTrue(cursor.isAfterLast());
  242. cursor.restoreSavepoint(savepoint);
  243. assertEquals(expectedRow, cursor.getCurrentRow());
  244. }
  245. @Test
  246. public void testMoveNoReset() throws Exception {
  247. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  248. Database db = createTestTable(fileFormat);
  249. Table table = db.getTable("test");
  250. Cursor cursor = CursorBuilder.createCursor(table);
  251. doTestMoveNoReset(cursor);
  252. db.close();
  253. }
  254. }
  255. private static void doTestMoveNoReset(Cursor cursor)
  256. throws Exception
  257. {
  258. List<Map<String, Object>> expectedRows = createTestTableData();
  259. List<Map<String, Object>> foundRows = new ArrayList<Map<String, Object>>();
  260. Iterator<Row> iter = cursor.newIterable().iterator();
  261. for(int i = 0; i < 6; ++i) {
  262. foundRows.add(iter.next());
  263. }
  264. iter = cursor.newIterable().reset(false).reverse().iterator();
  265. iter.next();
  266. Map<String, Object> row = iter.next();
  267. assertEquals(expectedRows.get(4), row);
  268. iter = cursor.newIterable().reset(false).iterator();
  269. iter.next();
  270. row = iter.next();
  271. assertEquals(expectedRows.get(5), row);
  272. iter.next();
  273. iter = cursor.newIterable().reset(false).iterator();
  274. for(int i = 6; i < 10; ++i) {
  275. foundRows.add(iter.next());
  276. }
  277. assertEquals(expectedRows, foundRows);
  278. }
  279. @Test
  280. public void testSearch() throws Exception {
  281. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  282. Database db = createTestTable(fileFormat);
  283. Table table = db.getTable("test");
  284. Cursor cursor = CursorBuilder.createCursor(table);
  285. doTestSearch(table, cursor, null, 42, -13);
  286. db.close();
  287. }
  288. }
  289. private static void doTestSearch(Table table, Cursor cursor, Index index,
  290. Integer... outOfRangeValues)
  291. throws Exception
  292. {
  293. assertTrue(cursor.findFirstRow(table.getColumn("id"), 3));
  294. assertEquals(createExpectedRow("id", 3,
  295. "value", "data" + 3),
  296. cursor.getCurrentRow());
  297. assertTrue(cursor.findFirstRow(createExpectedRow(
  298. "id", 6,
  299. "value", "data" + 6)));
  300. assertEquals(createExpectedRow("id", 6,
  301. "value", "data" + 6),
  302. cursor.getCurrentRow());
  303. assertFalse(cursor.findFirstRow(createExpectedRow(
  304. "id", 8,
  305. "value", "data" + 13)));
  306. assertFalse(cursor.findFirstRow(table.getColumn("id"), 13));
  307. assertEquals(createExpectedRow("id", 6,
  308. "value", "data" + 6),
  309. cursor.getCurrentRow());
  310. assertTrue(cursor.findFirstRow(createExpectedRow(
  311. "value", "data" + 7)));
  312. assertEquals(createExpectedRow("id", 7,
  313. "value", "data" + 7),
  314. cursor.getCurrentRow());
  315. assertTrue(cursor.findFirstRow(table.getColumn("value"), "data" + 4));
  316. assertEquals(createExpectedRow("id", 4,
  317. "value", "data" + 4),
  318. cursor.getCurrentRow());
  319. for(Integer outOfRangeValue : outOfRangeValues) {
  320. assertFalse(cursor.findFirstRow(table.getColumn("id"),
  321. outOfRangeValue));
  322. assertFalse(cursor.findFirstRow(table.getColumn("value"),
  323. "data" + outOfRangeValue));
  324. assertFalse(cursor.findFirstRow(createExpectedRow(
  325. "id", outOfRangeValue,
  326. "value", "data" + outOfRangeValue)));
  327. }
  328. assertEquals("data" + 5,
  329. CursorBuilder.findValue(table,
  330. table.getColumn("value"),
  331. table.getColumn("id"), 5));
  332. assertEquals(createExpectedRow("id", 5,
  333. "value", "data" + 5),
  334. CursorBuilder.findRow(table,
  335. createExpectedRow("id", 5)));
  336. if(index != null) {
  337. assertEquals("data" + 5,
  338. CursorBuilder.findValue(index,
  339. table.getColumn("value"),
  340. table.getColumn("id"), 5));
  341. assertEquals(createExpectedRow("id", 5,
  342. "value", "data" + 5),
  343. CursorBuilder.findRow(index,
  344. createExpectedRow("id", 5)));
  345. assertNull(CursorBuilder.findValue(index,
  346. table.getColumn("value"),
  347. table.getColumn("id"),
  348. -17));
  349. assertNull(CursorBuilder.findRow(index,
  350. createExpectedRow("id", 13)));
  351. }
  352. }
  353. @Test
  354. public void testReverse() throws Exception {
  355. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  356. Database db = createTestTable(fileFormat);
  357. Table table = db.getTable("test");
  358. Cursor cursor = CursorBuilder.createCursor(table);
  359. doTestReverse(cursor, null);
  360. db.close();
  361. }
  362. }
  363. private static void doTestReverse(Cursor cursor,
  364. List<Map<String, Object>> expectedRows)
  365. throws Exception
  366. {
  367. if(expectedRows == null) {
  368. expectedRows = createTestTableData();
  369. }
  370. Collections.reverse(expectedRows);
  371. List<Map<String, Object>> foundRows =
  372. new ArrayList<Map<String, Object>>();
  373. for(Map<String, Object> row : cursor.newIterable().reverse()) {
  374. foundRows.add(row);
  375. }
  376. assertEquals(expectedRows, foundRows);
  377. }
  378. @Test
  379. public void testLiveAddition() throws Exception {
  380. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  381. Database db = createTestTable(fileFormat);
  382. Table table = db.getTable("test");
  383. Cursor cursor1 = CursorBuilder.createCursor(table);
  384. Cursor cursor2 = CursorBuilder.createCursor(table);
  385. doTestLiveAddition(table, cursor1, cursor2, 11);
  386. db.close();
  387. }
  388. }
  389. private static void doTestLiveAddition(Table table,
  390. Cursor cursor1,
  391. Cursor cursor2,
  392. Integer newRowNum) throws Exception
  393. {
  394. cursor1.moveNextRows(11);
  395. cursor2.moveNextRows(11);
  396. assertTrue(cursor1.isAfterLast());
  397. assertTrue(cursor2.isAfterLast());
  398. table.addRow(newRowNum, "data" + newRowNum);
  399. Map<String,Object> expectedRow =
  400. createExpectedRow("id", newRowNum, "value", "data" + newRowNum);
  401. assertFalse(cursor1.isAfterLast());
  402. assertFalse(cursor2.isAfterLast());
  403. assertEquals(expectedRow, cursor1.getCurrentRow());
  404. assertEquals(expectedRow, cursor2.getCurrentRow());
  405. assertFalse(cursor1.moveToNextRow());
  406. assertFalse(cursor2.moveToNextRow());
  407. assertTrue(cursor1.isAfterLast());
  408. assertTrue(cursor2.isAfterLast());
  409. }
  410. @Test
  411. public void testLiveDeletion() throws Exception {
  412. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  413. Database db = createTestTable(fileFormat);
  414. Table table = db.getTable("test");
  415. Cursor cursor1 = CursorBuilder.createCursor(table);
  416. Cursor cursor2 = CursorBuilder.createCursor(table);
  417. Cursor cursor3 = CursorBuilder.createCursor(table);
  418. Cursor cursor4 = CursorBuilder.createCursor(table);
  419. doTestLiveDeletion(cursor1, cursor2, cursor3, cursor4, 1);
  420. db.close();
  421. }
  422. }
  423. private static void doTestLiveDeletion(
  424. Cursor cursor1,
  425. Cursor cursor2,
  426. Cursor cursor3,
  427. Cursor cursor4,
  428. int firstValue) throws Exception
  429. {
  430. assertEquals(2, cursor1.moveNextRows(2));
  431. assertEquals(3, cursor2.moveNextRows(3));
  432. assertEquals(3, cursor3.moveNextRows(3));
  433. assertEquals(4, cursor4.moveNextRows(4));
  434. Map<String,Object> expectedPrevRow =
  435. createExpectedRow("id", firstValue, "value", "data" + firstValue);
  436. ++firstValue;
  437. Map<String,Object> expectedDeletedRow =
  438. createExpectedRow("id", firstValue, "value", "data" + firstValue);
  439. ++firstValue;
  440. Map<String,Object> expectedNextRow =
  441. createExpectedRow("id", firstValue, "value", "data" + firstValue);
  442. assertEquals(expectedDeletedRow, cursor2.getCurrentRow());
  443. assertEquals(expectedDeletedRow, cursor3.getCurrentRow());
  444. assertFalse(cursor2.isCurrentRowDeleted());
  445. assertFalse(cursor3.isCurrentRowDeleted());
  446. cursor2.deleteCurrentRow();
  447. assertTrue(cursor2.isCurrentRowDeleted());
  448. assertTrue(cursor3.isCurrentRowDeleted());
  449. assertEquals(expectedNextRow, cursor1.getNextRow());
  450. assertEquals(expectedNextRow, cursor2.getNextRow());
  451. assertEquals(expectedNextRow, cursor3.getNextRow());
  452. assertEquals(expectedPrevRow, cursor3.getPreviousRow());
  453. assertTrue(cursor3.moveToNextRow());
  454. cursor3.deleteCurrentRow();
  455. assertTrue(cursor3.isCurrentRowDeleted());
  456. firstValue += 2;
  457. expectedNextRow =
  458. createExpectedRow("id", firstValue, "value", "data" + firstValue);
  459. assertTrue(cursor3.moveToNextRow());
  460. assertEquals(expectedNextRow, cursor3.getNextRow());
  461. cursor1.beforeFirst();
  462. assertTrue(cursor1.moveToNextRow());
  463. cursor1.deleteCurrentRow();
  464. assertFalse(cursor1.isBeforeFirst());
  465. assertFalse(cursor1.isAfterLast());
  466. assertFalse(cursor1.moveToPreviousRow());
  467. assertTrue(cursor1.isBeforeFirst());
  468. assertFalse(cursor1.isAfterLast());
  469. cursor1.afterLast();
  470. assertTrue(cursor1.moveToPreviousRow());
  471. cursor1.deleteCurrentRow();
  472. assertFalse(cursor1.isBeforeFirst());
  473. assertFalse(cursor1.isAfterLast());
  474. assertFalse(cursor1.moveToNextRow());
  475. assertFalse(cursor1.isBeforeFirst());
  476. assertTrue(cursor1.isAfterLast());
  477. cursor1.beforeFirst();
  478. while(cursor1.moveToNextRow()) {
  479. cursor1.deleteCurrentRow();
  480. }
  481. assertTrue(cursor1.isAfterLast());
  482. assertTrue(cursor2.isCurrentRowDeleted());
  483. assertTrue(cursor3.isCurrentRowDeleted());
  484. assertTrue(cursor4.isCurrentRowDeleted());
  485. }
  486. @Test
  487. public void testSimpleIndex() throws Exception {
  488. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  489. Database db = createTestIndexTable(indexCursorDB);
  490. Table table = db.getTable("test");
  491. Index idx = table.getIndexes().get(0);
  492. assertTable(createUnorderedTestTableData(), table);
  493. Cursor cursor = CursorBuilder.createCursor(idx);
  494. doTestSimple(cursor, null);
  495. db.close();
  496. }
  497. }
  498. @Test
  499. public void testMoveIndex() throws Exception {
  500. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  501. Database db = createTestIndexTable(indexCursorDB);
  502. Table table = db.getTable("test");
  503. Index idx = table.getIndexes().get(0);
  504. Cursor cursor = CursorBuilder.createCursor(idx);
  505. doTestMove(cursor, null);
  506. db.close();
  507. }
  508. }
  509. @Test
  510. public void testReverseIndex() throws Exception {
  511. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  512. Database db = createTestIndexTable(indexCursorDB);
  513. Table table = db.getTable("test");
  514. Index idx = table.getIndexes().get(0);
  515. Cursor cursor = CursorBuilder.createCursor(idx);
  516. doTestReverse(cursor, null);
  517. db.close();
  518. }
  519. }
  520. @Test
  521. public void testSearchIndex() throws Exception {
  522. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  523. Database db = createTestIndexTable(indexCursorDB);
  524. Table table = db.getTable("test");
  525. Index idx = table.getIndexes().get(0);
  526. Cursor cursor = CursorBuilder.createCursor(idx);
  527. doTestSearch(table, cursor, idx, 42, -13);
  528. db.close();
  529. }
  530. }
  531. @Test
  532. public void testLiveAdditionIndex() throws Exception {
  533. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  534. Database db = createTestIndexTable(indexCursorDB);
  535. Table table = db.getTable("test");
  536. Index idx = table.getIndexes().get(0);
  537. Cursor cursor1 = CursorBuilder.createCursor(idx);
  538. Cursor cursor2 = CursorBuilder.createCursor(idx);
  539. doTestLiveAddition(table, cursor1, cursor2, 11);
  540. db.close();
  541. }
  542. }
  543. @Test
  544. public void testLiveDeletionIndex() throws Exception {
  545. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  546. Database db = createTestIndexTable(indexCursorDB);
  547. Table table = db.getTable("test");
  548. Index idx = table.getIndexes().get(0);
  549. Cursor cursor1 = CursorBuilder.createCursor(idx);
  550. Cursor cursor2 = CursorBuilder.createCursor(idx);
  551. Cursor cursor3 = CursorBuilder.createCursor(idx);
  552. Cursor cursor4 = CursorBuilder.createCursor(idx);
  553. doTestLiveDeletion(cursor1, cursor2, cursor3, cursor4, 1);
  554. db.close();
  555. }
  556. }
  557. @Test
  558. public void testSimpleIndexSubRange() throws Exception {
  559. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  560. for(int i = 0; i < 2; ++i) {
  561. Database db = createTestIndexTable(indexCursorDB);
  562. Table table = db.getTable("test");
  563. Index idx = table.getIndexes().get(0);
  564. Cursor cursor = createIndexSubRangeCursor(table, idx, i);
  565. List<Map<String,Object>> expectedRows =
  566. createTestTableData(3, 9);
  567. doTestSimple(cursor, expectedRows);
  568. db.close();
  569. }
  570. }
  571. }
  572. @Test
  573. public void testMoveIndexSubRange() throws Exception {
  574. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  575. for(int i = 0; i < 2; ++i) {
  576. Database db = createTestIndexTable(indexCursorDB);
  577. Table table = db.getTable("test");
  578. Index idx = table.getIndexes().get(0);
  579. Cursor cursor = createIndexSubRangeCursor(table, idx, i);
  580. List<Map<String,Object>> expectedRows =
  581. createTestTableData(3, 9);
  582. doTestMove(cursor, expectedRows);
  583. db.close();
  584. }
  585. }
  586. }
  587. @Test
  588. public void testSearchIndexSubRange() throws Exception {
  589. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  590. for(int i = 0; i < 2; ++i) {
  591. Database db = createTestIndexTable(indexCursorDB);
  592. Table table = db.getTable("test");
  593. Index idx = table.getIndexes().get(0);
  594. Cursor cursor = createIndexSubRangeCursor(table, idx, i);
  595. doTestSearch(table, cursor, idx, 2, 9);
  596. db.close();
  597. }
  598. }
  599. }
  600. @Test
  601. public void testReverseIndexSubRange() throws Exception {
  602. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  603. for(int i = 0; i < 2; ++i) {
  604. Database db = createTestIndexTable(indexCursorDB);
  605. Table table = db.getTable("test");
  606. Index idx = table.getIndexes().get(0);
  607. Cursor cursor = createIndexSubRangeCursor(table, idx, i);
  608. List<Map<String,Object>> expectedRows =
  609. createTestTableData(3, 9);
  610. doTestReverse(cursor, expectedRows);
  611. db.close();
  612. }
  613. }
  614. }
  615. @Test
  616. public void testLiveAdditionIndexSubRange() throws Exception {
  617. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  618. for(int i = 0; i < 2; ++i) {
  619. Database db = createTestIndexTable(indexCursorDB);
  620. Table table = db.getTable("test");
  621. Index idx = table.getIndexes().get(0);
  622. Cursor cursor1 = createIndexSubRangeCursor(table, idx, i);
  623. Cursor cursor2 = createIndexSubRangeCursor(table, idx, i);
  624. doTestLiveAddition(table, cursor1, cursor2, 8);
  625. db.close();
  626. }
  627. }
  628. }
  629. @Test
  630. public void testLiveDeletionIndexSubRange() throws Exception {
  631. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  632. for(int i = 0; i < 2; ++i) {
  633. Database db = createTestIndexTable(indexCursorDB);
  634. Table table = db.getTable("test");
  635. Index idx = table.getIndexes().get(0);
  636. Cursor cursor1 = createIndexSubRangeCursor(table, idx, i);
  637. Cursor cursor2 = createIndexSubRangeCursor(table, idx, i);
  638. Cursor cursor3 = createIndexSubRangeCursor(table, idx, i);
  639. Cursor cursor4 = createIndexSubRangeCursor(table, idx, i);
  640. doTestLiveDeletion(cursor1, cursor2, cursor3, cursor4, 4);
  641. db.close();
  642. }
  643. }
  644. }
  645. @Test
  646. public void testFindAllIndex() throws Exception {
  647. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  648. Database db = createDupeTestTable(fileFormat);
  649. Table table = db.getTable("test");
  650. Cursor cursor = CursorBuilder.createCursor(table);
  651. doTestFindAll(table, cursor, null);
  652. db.close();
  653. }
  654. }
  655. @Test
  656. public void testFindAll() throws Exception {
  657. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  658. Database db = createDupeTestTable(indexCursorDB);
  659. Table table = db.getTable("test");
  660. Index idx = table.getIndexes().get(0);
  661. Cursor cursor = CursorBuilder.createCursor(idx);
  662. doTestFindAll(table, cursor, idx);
  663. db.close();
  664. }
  665. }
  666. private static void doTestFindAll(Table table, Cursor cursor, Index index)
  667. throws Exception
  668. {
  669. List<? extends Map<String,Object>> rows = RowFilterTest.toList(
  670. cursor.newIterable().setMatchPattern("value", "data2"));
  671. List<? extends Map<String, Object>> expectedRows = null;
  672. if(index == null) {
  673. expectedRows =
  674. createExpectedTable(
  675. createExpectedRow(
  676. "id", 2, "value", "data2"),
  677. createExpectedRow(
  678. "id", 5, "value", "data2"),
  679. createExpectedRow(
  680. "id", 8, "value", "data2"),
  681. createExpectedRow(
  682. "id", 7, "value", "data2"),
  683. createExpectedRow(
  684. "id", 2, "value", "data2"));
  685. } else {
  686. expectedRows =
  687. createExpectedTable(
  688. createExpectedRow(
  689. "id", 2, "value", "data2"),
  690. createExpectedRow(
  691. "id", 2, "value", "data2"),
  692. createExpectedRow(
  693. "id", 5, "value", "data2"),
  694. createExpectedRow(
  695. "id", 7, "value", "data2"),
  696. createExpectedRow(
  697. "id", 8, "value", "data2"));
  698. }
  699. assertEquals(expectedRows, rows);
  700. Column valCol = table.getColumn("value");
  701. rows = RowFilterTest.toList(
  702. cursor.newIterable().setMatchPattern(valCol, "data4"));
  703. if(index == null) {
  704. expectedRows =
  705. createExpectedTable(
  706. createExpectedRow(
  707. "id", 9, "value", "data4"),
  708. createExpectedRow(
  709. "id", 4, "value", "data4"));
  710. } else {
  711. expectedRows =
  712. createExpectedTable(
  713. createExpectedRow(
  714. "id", 4, "value", "data4"),
  715. createExpectedRow(
  716. "id", 9, "value", "data4"));
  717. }
  718. assertEquals(expectedRows, rows);
  719. rows = RowFilterTest.toList(
  720. cursor.newIterable().setMatchPattern(valCol, "data9"));
  721. assertTrue(rows.isEmpty());
  722. rows = RowFilterTest.toList(
  723. cursor.newIterable().setMatchPattern(
  724. Collections.singletonMap("id", 8)));
  725. expectedRows =
  726. createExpectedTable(
  727. createExpectedRow(
  728. "id", 8, "value", "data2"),
  729. createExpectedRow(
  730. "id", 8, "value", "data3"));
  731. assertEquals(expectedRows, rows);
  732. for(Map<String,Object> row : table) {
  733. List<Map<String,Object>> tmpRows = new ArrayList<Map<String,Object>>();
  734. for(Map<String,Object> tmpRow : cursor) {
  735. if(row.equals(tmpRow)) {
  736. tmpRows.add(tmpRow);
  737. }
  738. }
  739. expectedRows = tmpRows;
  740. assertFalse(expectedRows.isEmpty());
  741. rows = RowFilterTest.toList(cursor.newIterable().setMatchPattern(row));
  742. assertEquals(expectedRows, rows);
  743. }
  744. rows = RowFilterTest.toList(
  745. cursor.newIterable().addMatchPattern("id", 8)
  746. .addMatchPattern("value", "data13"));
  747. assertTrue(rows.isEmpty());
  748. }
  749. @Test
  750. public void testId() throws Exception
  751. {
  752. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  753. Database db = createTestIndexTable(indexCursorDB);
  754. Table table = db.getTable("test");
  755. Index idx = table.getIndexes().get(0);
  756. Cursor tCursor = CursorBuilder.createCursor(table);
  757. Cursor iCursor = CursorBuilder.createCursor(idx);
  758. Cursor.Savepoint tSave = tCursor.getSavepoint();
  759. Cursor.Savepoint iSave = iCursor.getSavepoint();
  760. tCursor.restoreSavepoint(tSave);
  761. iCursor.restoreSavepoint(iSave);
  762. assertThrows(IllegalArgumentException.class, () -> tCursor.restoreSavepoint(iSave));
  763. assertThrows(IllegalArgumentException.class, () -> iCursor.restoreSavepoint(tSave));
  764. Cursor tCursor2 = CursorBuilder.createCursor(table);
  765. Cursor iCursor2 = CursorBuilder.createCursor(idx);
  766. tCursor2.restoreSavepoint(tSave);
  767. iCursor2.restoreSavepoint(iSave);
  768. db.close();
  769. }
  770. }
  771. @Test
  772. public void testColumnMatcher() throws Exception {
  773. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  774. Database db = createTestTable(fileFormat);
  775. Table table = db.getTable("test");
  776. doTestMatchers(table, SimpleColumnMatcher.INSTANCE, false);
  777. doTestMatchers(table, CaseInsensitiveColumnMatcher.INSTANCE, true);
  778. Cursor cursor = CursorBuilder.createCursor(table);
  779. doTestMatcher(table, cursor, SimpleColumnMatcher.INSTANCE, false);
  780. doTestMatcher(table, cursor, CaseInsensitiveColumnMatcher.INSTANCE,
  781. true);
  782. db.close();
  783. }
  784. }
  785. private static void doTestMatchers(Table table, ColumnMatcher columnMatcher,
  786. boolean caseInsensitive)
  787. throws Exception
  788. {
  789. assertTrue(columnMatcher.matches(table, "value", null, null));
  790. assertFalse(columnMatcher.matches(table, "value", "foo", null));
  791. assertFalse(columnMatcher.matches(table, "value", null, "foo"));
  792. assertTrue(columnMatcher.matches(table, "value", "foo", "foo"));
  793. assertTrue(columnMatcher.matches(table, "value", "foo", "Foo")
  794. == caseInsensitive);
  795. assertFalse(columnMatcher.matches(table, "value", 13, null));
  796. assertFalse(columnMatcher.matches(table, "value", null, 13));
  797. assertTrue(columnMatcher.matches(table, "value", 13, 13));
  798. }
  799. private static void doTestMatcher(Table table, Cursor cursor,
  800. ColumnMatcher columnMatcher,
  801. boolean caseInsensitive)
  802. throws Exception
  803. {
  804. cursor.setColumnMatcher(columnMatcher);
  805. assertTrue(cursor.findFirstRow(table.getColumn("id"), 3));
  806. assertEquals(createExpectedRow("id", 3,
  807. "value", "data" + 3),
  808. cursor.getCurrentRow());
  809. assertTrue(cursor.findFirstRow(createExpectedRow(
  810. "id", 6,
  811. "value", "data" + 6)));
  812. assertEquals(createExpectedRow("id", 6,
  813. "value", "data" + 6),
  814. cursor.getCurrentRow());
  815. assertTrue(cursor.findFirstRow(createExpectedRow(
  816. "id", 6,
  817. "value", "Data" + 6)) == caseInsensitive);
  818. if(caseInsensitive) {
  819. assertEquals(createExpectedRow("id", 6,
  820. "value", "data" + 6),
  821. cursor.getCurrentRow());
  822. }
  823. assertFalse(cursor.findFirstRow(createExpectedRow(
  824. "id", 8,
  825. "value", "data" + 13)));
  826. assertFalse(cursor.findFirstRow(table.getColumn("id"), 13));
  827. assertEquals(createExpectedRow("id", 6,
  828. "value", "data" + 6),
  829. cursor.getCurrentRow());
  830. assertTrue(cursor.findFirstRow(createExpectedRow(
  831. "value", "data" + 7)));
  832. assertEquals(createExpectedRow("id", 7,
  833. "value", "data" + 7),
  834. cursor.getCurrentRow());
  835. assertTrue(cursor.findFirstRow(createExpectedRow(
  836. "value", "Data" + 7)) == caseInsensitive);
  837. if(caseInsensitive) {
  838. assertEquals(createExpectedRow("id", 7,
  839. "value", "data" + 7),
  840. cursor.getCurrentRow());
  841. }
  842. assertTrue(cursor.findFirstRow(table.getColumn("value"), "data" + 4));
  843. assertEquals(createExpectedRow("id", 4,
  844. "value", "data" + 4),
  845. cursor.getCurrentRow());
  846. assertTrue(cursor.findFirstRow(table.getColumn("value"), "Data" + 4)
  847. == caseInsensitive);
  848. if(caseInsensitive) {
  849. assertEquals(createExpectedRow("id", 4,
  850. "value", "data" + 4),
  851. cursor.getCurrentRow());
  852. }
  853. assertEquals(Arrays.asList(createExpectedRow("id", 4,
  854. "value", "data" + 4)),
  855. RowFilterTest.toList(
  856. cursor.newIterable()
  857. .setMatchPattern("value", "data4")
  858. .setColumnMatcher(SimpleColumnMatcher.INSTANCE)));
  859. assertEquals(Arrays.asList(createExpectedRow("id", 3,
  860. "value", "data" + 3)),
  861. RowFilterTest.toList(
  862. cursor.newIterable()
  863. .setMatchPattern("value", "DaTa3")
  864. .setColumnMatcher(CaseInsensitiveColumnMatcher.INSTANCE)));
  865. assertEquals(Arrays.asList(createExpectedRow("id", 2,
  866. "value", "data" + 2)),
  867. RowFilterTest.toList(
  868. cursor.newIterable()
  869. .addMatchPattern("value", "DaTa2")
  870. .addMatchPattern("id", 2)
  871. .setColumnMatcher(CaseInsensitiveColumnMatcher.INSTANCE)));
  872. }
  873. @Test
  874. public void testIndexCursor() throws Exception
  875. {
  876. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX, true)) {
  877. Database db = openMem(testDB);
  878. Table t1 = db.getTable("Table1");
  879. Index idx = t1.getIndex(IndexBuilder.PRIMARY_KEY_NAME);
  880. IndexCursor cursor = CursorBuilder.createCursor(idx);
  881. assertFalse(cursor.findFirstRowByEntry(-1));
  882. cursor.findClosestRowByEntry(-1);
  883. assertEquals(0, cursor.getCurrentRow().get("id"));
  884. assertTrue(cursor.findFirstRowByEntry(1));
  885. assertEquals(1, cursor.getCurrentRow().get("id"));
  886. cursor.findClosestRowByEntry(2);
  887. assertEquals(2, cursor.getCurrentRow().get("id"));
  888. assertFalse(cursor.findFirstRowByEntry(4));
  889. cursor.findClosestRowByEntry(4);
  890. assertTrue(cursor.isAfterLast());
  891. db.close();
  892. }
  893. }
  894. @Test
  895. public void testIndexCursorDelete() throws Exception
  896. {
  897. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX)) {
  898. Database db = openMem(testDB);
  899. Table t1 = db.getTable("Table1");
  900. Index idx = t1.getIndex("Table2Table1");
  901. IndexCursor cursor = CursorBuilder.createCursor(idx);
  902. List<String> expectedData = cursor.newEntryIterable(1)
  903. .addColumnNames("data")
  904. .stream().map(r -> r.getString("data"))
  905. .collect(Collectors.toList());
  906. assertEquals(Arrays.asList("baz11", "baz11-2"), expectedData);
  907. expectedData = new ArrayList<String>();
  908. for(Iterator<? extends Row> iter =
  909. cursor.newEntryIterable(1).iterator();
  910. iter.hasNext(); ) {
  911. expectedData.add(iter.next().getString("data"));
  912. iter.remove();
  913. assertThrows(IllegalStateException.class, () -> iter.remove());
  914. if (!iter.hasNext()) {
  915. assertThrows(NoSuchElementException.class, () -> iter.next());
  916. }
  917. }
  918. assertEquals(Arrays.asList("baz11", "baz11-2"), expectedData);
  919. expectedData = new ArrayList<String>();
  920. for(Row row : cursor.newEntryIterable(1)
  921. .addColumnNames("data")) {
  922. expectedData.add(row.getString("data"));
  923. }
  924. assertTrue(expectedData.isEmpty());
  925. db.close();
  926. }
  927. }
  928. @Test
  929. public void testCursorDelete() throws Exception
  930. {
  931. for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.INDEX)) {
  932. Database db = openMem(testDB);
  933. Table t1 = db.getTable("Table1");
  934. Cursor cursor = CursorBuilder.createCursor(t1);
  935. List<String> expectedData = cursor.newIterable().setColumnNames(
  936. Arrays.asList("otherfk1", "data")).stream()
  937. .filter(r -> r.get("otherfk1").equals(1))
  938. .map(r -> r.getString("data"))
  939. .collect(Collectors.toList());
  940. assertEquals(Arrays.asList("baz11", "baz11-2"), expectedData);
  941. expectedData = new ArrayList<String>();
  942. for(Iterator<? extends Row> iter = cursor.iterator();
  943. iter.hasNext(); ) {
  944. Row row = iter.next();
  945. if(row.get("otherfk1").equals(1)) {
  946. expectedData.add(row.getString("data"));
  947. iter.remove();
  948. assertThrows(IllegalStateException.class, () -> iter.remove());
  949. }
  950. if (!iter.hasNext()) {
  951. assertThrows(NoSuchElementException.class, () -> iter.next());
  952. }
  953. }
  954. assertEquals(Arrays.asList("baz11", "baz11-2"), expectedData);
  955. expectedData = new ArrayList<String>();
  956. for(Row row : cursor.newIterable().setColumnNames(
  957. Arrays.asList("otherfk1", "data"))) {
  958. if(row.get("otherfk1").equals(1)) {
  959. expectedData.add(row.getString("data"));
  960. }
  961. }
  962. assertTrue(expectedData.isEmpty());
  963. db.close();
  964. }
  965. }
  966. @Test
  967. public void testFindByRowId() throws Exception {
  968. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  969. Database db = createTestTable(fileFormat);
  970. Table table = db.getTable("test");
  971. Cursor cursor = CursorBuilder.createCursor(table);
  972. doTestFindByRowId(cursor);
  973. db.close();
  974. }
  975. }
  976. @Test
  977. public void testFindByRowIdIndex() throws Exception {
  978. for (final TestDB indexCursorDB : INDEX_CURSOR_DBS) {
  979. Database db = createTestIndexTable(indexCursorDB);
  980. Table table = db.getTable("test");
  981. Index idx = table.getIndexes().get(0);
  982. assertTable(createUnorderedTestTableData(), table);
  983. Cursor cursor = CursorBuilder.createCursor(idx);
  984. doTestFindByRowId(cursor);
  985. db.close();
  986. }
  987. }
  988. private static void doTestFindByRowId(Cursor cursor)
  989. throws Exception
  990. {
  991. for(int i = 0; i < 3; ++i) {
  992. cursor.moveToNextRow();
  993. }
  994. Row r1 = cursor.getCurrentRow();
  995. for(int i = 0; i < 3; ++i) {
  996. cursor.moveToNextRow();
  997. }
  998. Row r2 = cursor.getCurrentRow();
  999. doTestFindByRowId(cursor, r1, 2);
  1000. doTestFindByRowId(cursor, r2, 5);
  1001. }
  1002. private static void doTestFindByRowId(Cursor cursor, Row row, int id)
  1003. throws Exception
  1004. {
  1005. cursor.reset();
  1006. assertTrue(cursor.findRow(row.getId()));
  1007. Row rFound = cursor.getCurrentRow();
  1008. assertEquals(id, rFound.get("id"));
  1009. assertEquals(row, rFound);
  1010. Cursor.Savepoint save = cursor.getSavepoint();
  1011. assertTrue(cursor.moveToNextRow());
  1012. assertEquals(id + 1, cursor.getCurrentRow().get("id"));
  1013. cursor.restoreSavepoint(save);
  1014. assertTrue(cursor.moveToPreviousRow());
  1015. assertEquals(id - 1, cursor.getCurrentRow().get("id"));
  1016. assertFalse(cursor.findRow(RowIdImpl.FIRST_ROW_ID));
  1017. assertEquals(id - 1, cursor.getCurrentRow().get("id"));
  1018. }
  1019. @Test
  1020. public void testIterationEarlyExit() throws Exception {
  1021. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  1022. Database db = createMem(fileFormat);
  1023. Table table = newTable("test")
  1024. .addColumn(newColumn("id", DataType.LONG))
  1025. .addColumn(newColumn("value", DataType.TEXT))
  1026. .addColumn(newColumn("memo", DataType.MEMO))
  1027. .addIndex(newIndex("value_idx")
  1028. .addColumns("value"))
  1029. .toTable(db);
  1030. for(int i = 0; i < 20; ++i) {
  1031. Object memo = "memo-" + i;
  1032. table.addRow(i, "val-" + (i/2), memo);
  1033. }
  1034. // generate an "invalid" memo
  1035. byte[] b = new byte[12];
  1036. b[3] = (byte)0xC0;
  1037. table.addRow(20, "val-9", ColumnImpl.rawDataWrapper(b));
  1038. IndexCursor cursor = CursorBuilder.createCursor(
  1039. table.getIndex("value_idx"));
  1040. assertThrows(RuntimeIOException.class, () -> cursor.newIterable()
  1041. .addMatchPattern("value", "val-9")
  1042. .addMatchPattern("memo", "anything")
  1043. .iterator().hasNext());
  1044. List<Row> rows = new ArrayList<Row>();
  1045. for (Row row : cursor.newIterable()
  1046. .addMatchPattern("value", "val-5")
  1047. .addMatchPattern("memo", "memo-11")) {
  1048. rows.add(row);
  1049. }
  1050. assertEquals(rows, createExpectedTable(
  1051. createExpectedRow("id", 11,
  1052. "value", "val-5",
  1053. "memo", "memo-11")));
  1054. assertFalse(cursor.newIterable()
  1055. .addMatchPattern("value", "val-31")
  1056. .addMatchPattern("memo", "anything")
  1057. .iterator().hasNext());
  1058. db.close();
  1059. }
  1060. }
  1061. @Test
  1062. public void testPartialIndexFind() throws Exception
  1063. {
  1064. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  1065. Database db = createMem(fileFormat);
  1066. TableImpl t = (TableImpl)newTable("Test")
  1067. .addColumn(newColumn("id", DataType.LONG))
  1068. .addColumn(newColumn("data1", DataType.TEXT))
  1069. .addColumn(newColumn("num2", DataType.LONG))
  1070. .addColumn(newColumn("key3", DataType.TEXT))
  1071. .addColumn(newColumn("value", DataType.TEXT))
  1072. .addIndex(newIndex("idx3").addColumns("data1", "num2", "key3"))
  1073. .toTable(db);
  1074. Index idx = t.findIndexForColumns(Arrays.asList("data1"),
  1075. TableImpl.IndexFeature.ANY_MATCH);
  1076. assertEquals("idx3", idx.getName());
  1077. idx = t.findIndexForColumns(Arrays.asList("data1", "num2"),
  1078. TableImpl.IndexFeature.ANY_MATCH);
  1079. assertEquals("idx3", idx.getName());
  1080. idx = t.findIndexForColumns(Arrays.asList("data1", "num2", "key3"),
  1081. TableImpl.IndexFeature.ANY_MATCH);
  1082. assertEquals("idx3", idx.getName());
  1083. assertNull(t.findIndexForColumns(Arrays.asList("num2"),
  1084. TableImpl.IndexFeature.ANY_MATCH));
  1085. assertNull(t.findIndexForColumns(Arrays.asList("data1", "key3"),
  1086. TableImpl.IndexFeature.ANY_MATCH));
  1087. assertNull(t.findIndexForColumns(Arrays.asList("data1"),
  1088. TableImpl.IndexFeature.EXACT_MATCH));
  1089. newIndex("idx2")
  1090. .addColumns("data1", "num2")
  1091. .addToTable(t);
  1092. idx = t.findIndexForColumns(Arrays.asList("data1"),
  1093. TableImpl.IndexFeature.ANY_MATCH);
  1094. assertEquals("idx2", idx.getName());
  1095. idx = t.findIndexForColumns(Arrays.asList("data1", "num2"),
  1096. TableImpl.IndexFeature.ANY_MATCH);
  1097. assertEquals("idx2", idx.getName());
  1098. idx = t.findIndexForColumns(Arrays.asList("data1", "num2", "key3"),
  1099. TableImpl.IndexFeature.ANY_MATCH);
  1100. assertEquals("idx3", idx.getName());
  1101. assertNull(t.findIndexForColumns(Arrays.asList("num2"),
  1102. TableImpl.IndexFeature.ANY_MATCH));
  1103. assertNull(t.findIndexForColumns(Arrays.asList("data1", "key3"),
  1104. TableImpl.IndexFeature.ANY_MATCH));
  1105. assertNull(t.findIndexForColumns(Arrays.asList("data1"),
  1106. TableImpl.IndexFeature.EXACT_MATCH));
  1107. newIndex("idx1")
  1108. .addColumns("data1")
  1109. .addToTable(t);
  1110. idx = t.findIndexForColumns(Arrays.asList("data1"),
  1111. TableImpl.IndexFeature.ANY_MATCH);
  1112. assertEquals("idx1", idx.getName());
  1113. idx = t.findIndexForColumns(Arrays.asList("data1", "num2"),
  1114. TableImpl.IndexFeature.ANY_MATCH);
  1115. assertEquals("idx2", idx.getName());
  1116. idx = t.findIndexForColumns(Arrays.asList("data1", "num2", "key3"),
  1117. TableImpl.IndexFeature.ANY_MATCH);
  1118. assertEquals("idx3", idx.getName());
  1119. assertNull(t.findIndexForColumns(Arrays.asList("num2"),
  1120. TableImpl.IndexFeature.ANY_MATCH));
  1121. assertNull(t.findIndexForColumns(Arrays.asList("data1", "key3"),
  1122. TableImpl.IndexFeature.ANY_MATCH));
  1123. db.close();
  1124. }
  1125. }
  1126. @Test
  1127. public void testPartialIndexLookup() throws Exception
  1128. {
  1129. for (final FileFormat fileFormat : JetFormatTest.SUPPORTED_FILEFORMATS) {
  1130. Database db = createMem(fileFormat);
  1131. TableImpl t = (TableImpl)newTable("Test")
  1132. .addColumn(newColumn("id", DataType.LONG))
  1133. .addColumn(newColumn("data1", DataType.TEXT))
  1134. .addColumn(newColumn("num2", DataType.LONG))
  1135. .addColumn(newColumn("key3", DataType.TEXT))
  1136. .addColumn(newColumn("value", DataType.TEXT))
  1137. .addIndex(newIndex("idx3")
  1138. .addColumns(true, "data1")
  1139. .addColumns(false, "num2")
  1140. .addColumns(true, "key3")
  1141. )
  1142. .toTable(db);
  1143. int id = 1;
  1144. for(String str : Arrays.asList("A", "B", "C", "D")) {
  1145. for(int i = 4; i >= 0; --i) {
  1146. // for(int i = 0; i < 5; ++i) {
  1147. for(int j = 1; j < 3; ++j) {
  1148. t.addRow(id, str, i, "K" + j, "value" + id);
  1149. ++id;
  1150. }
  1151. }
  1152. }
  1153. Index idx = t.getIndex("idx3");
  1154. doPartialIndexLookup(idx);
  1155. idx = newIndex("idx2")
  1156. .addColumns(true, "data1")
  1157. .addColumns(false, "num2")
  1158. .addToTable(t);
  1159. doPartialIndexLookup(idx);
  1160. idx = newIndex("idx1")
  1161. .addColumns(true, "data1")
  1162. .addToTable(t);
  1163. doPartialIndexLookup(idx);
  1164. db.close();
  1165. }
  1166. }
  1167. private static void doPartialIndexLookup(Index idx) throws Exception
  1168. {
  1169. int colCount = idx.getColumnCount();
  1170. IndexCursor c = idx.newCursor().toIndexCursor();
  1171. doFindFirstByEntry(c, 21, "C");
  1172. doFindFirstByEntry(c, null, "Z");
  1173. if(colCount > 1) {
  1174. doFindFirstByEntry(c, 23, "C", 3);
  1175. doFindFirstByEntry(c, null, "C", 20);
  1176. }
  1177. if(colCount > 2) {
  1178. doFindFirstByEntry(c, 27, "C", 1, "K1");
  1179. doFindFirstByEntry(c, null, "C", 4, "K3");
  1180. }
  1181. assertThrows(IllegalArgumentException.class, () ->
  1182. {
  1183. if (colCount > 2) {
  1184. c.findFirstRowByEntry("C", 4, "K1", 14);
  1185. } else if(colCount > 1) {
  1186. c.findFirstRowByEntry("C", 4, "K1");
  1187. } else {
  1188. c.findFirstRowByEntry("C", 4);
  1189. }
  1190. });
  1191. doFindByEntryRange(c, 11, 20, "B");
  1192. doFindByEntry(c, new int[]{}, "Z");
  1193. if(colCount > 1) {
  1194. doFindByEntryRange(c, 13, 14, "B", 3);
  1195. doFindByEntry(c, new int[]{}, "B", 20);
  1196. }
  1197. if(colCount > 2) {
  1198. doFindByEntryRange(c, 14, 14, "B", 3, "K2");
  1199. doFindByEntry(c, new int[]{}, "B", 3, "K3");
  1200. }
  1201. doFindByRow(idx, 13,
  1202. "data1", "B", "value", "value13");
  1203. doFindByRow(idx, 13,
  1204. "data1", "B", "key3", "K1", "value", "value13");
  1205. doFindByRow(idx, 13,
  1206. "data1", "B", "num2", 3, "key3", "K1", "value", "value13");
  1207. doFindByRow(idx, 13,
  1208. "num2", 3, "value", "value13");
  1209. doFindByRow(idx, 13,
  1210. "value", "value13");
  1211. doFindByRow(idx, null,
  1212. "data1", "B", "num2", 5, "key3", "K1", "value", "value13");
  1213. doFindByRow(idx, null,
  1214. "data1", "B", "value", "value4");
  1215. Column col = idx.getTable().getColumn("data1");
  1216. doFindValue(idx, 21, col, "C");
  1217. doFindValue(idx, null, col, "Z");
  1218. col = idx.getTable().getColumn("value");
  1219. doFindValue(idx, 21, col, "value21");
  1220. doFindValue(idx, null, col, "valueZ");
  1221. }
  1222. private static void doFindFirstByEntry(IndexCursor c, Integer expectedId,
  1223. Object... entry)
  1224. throws Exception
  1225. {
  1226. if(expectedId != null) {
  1227. assertTrue(c.findFirstRowByEntry(entry));
  1228. assertEquals(expectedId, c.getCurrentRow().get("id"));
  1229. } else {
  1230. assertFalse(c.findFirstRowByEntry(entry));
  1231. }
  1232. }
  1233. private static void doFindByEntryRange(IndexCursor c, int start, int end,
  1234. Object... entry)
  1235. {
  1236. List<Integer> expectedIds = new ArrayList<Integer>();
  1237. for(int i = start; i <= end; ++i) {
  1238. expectedIds.add(i);
  1239. }
  1240. doFindByEntry(c, expectedIds, entry);
  1241. }
  1242. private static void doFindByEntry(IndexCursor c, int[] ids,
  1243. Object... entry)
  1244. {
  1245. List<Integer> expectedIds = new ArrayList<Integer>();
  1246. for(int id : ids) {
  1247. expectedIds.add(id);
  1248. }
  1249. doFindByEntry(c, expectedIds, entry);
  1250. }
  1251. private static void doFindByEntry(IndexCursor c, List<Integer> expectedIds,
  1252. Object... entry)
  1253. {
  1254. List<Integer> foundIds = new ArrayList<Integer>();
  1255. for(Row row : c.newEntryIterable(entry)) {
  1256. foundIds.add((Integer)row.get("id"));
  1257. }
  1258. assertEquals(expectedIds, foundIds);
  1259. }
  1260. private static void doFindByRow(Index idx, Integer id, Object... rowPairs)
  1261. throws Exception
  1262. {
  1263. Map<String,Object> map = createExpectedRow(
  1264. rowPairs);
  1265. Row r = CursorBuilder.findRow(idx, map);
  1266. if(id != null) {
  1267. assertEquals(id, r.get("id"));
  1268. } else {
  1269. assertNull(r);
  1270. }
  1271. }
  1272. private static void doFindValue(Index idx, Integer id,
  1273. Column columnPattern, Object valuePattern)
  1274. throws Exception
  1275. {
  1276. Object value = CursorBuilder.findValue(
  1277. idx, idx.getTable().getColumn("id"), columnPattern, valuePattern);
  1278. if(id != null) {
  1279. assertEquals(id, value);
  1280. } else {
  1281. assertNull(value);
  1282. }
  1283. }
  1284. }