private void iterateRecords(boolean testStoredDB, int schemaType, int recordCnt,
			long keyIncrement, int varDataSize, boolean doUndoRedo) throws IOException {

		DBRecord[] recs = null;
		if (keyIncrement == 0) {
			recs = createRandomTableRecords(schemaType, recordCnt, varDataSize);
		}
		else {
			recs = createOrderedTableRecords(schemaType, recordCnt, keyIncrement, varDataSize);
		}

		if (testStoredDB) {
			saveAsAndReopen(dbName);
		}
		Table table = dbh.getTable(table1Name);
		assertEquals(recordCnt, table.getRecordCount());

		if (doUndoRedo) {
			dbh.undo();
			dbh.redo();
			table = dbh.getTable(table1Name);
			assertEquals(recordCnt, table.getRecordCount());
		}

		for (int colIx : table.getIndexedColumns()) {
			Arrays.sort(recs, new RecColumnComparator(colIx));

			int recIx;
			RecordIterator iter;
			ArrayList<Field> indexFields = new ArrayList<>();// list of unique index field values

			// Forward iteration (default iterator with no start) - also collect unique fields
			Field lastIndex = null;
			recIx = 0;
			iter = table.indexIterator(colIx);
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx], rec);
				Field indexField = recs[recIx].getField(colIx);
				if (lastIndex == null || !lastIndex.equals(indexField)) {
					indexFields.add(indexField);
					lastIndex = indexField;
				}
				++recIx;
			}
			assertEquals(recordCnt, recIx);

			// Backward iteration (default iterator with no start)
			recIx = 0;
			iter = table.indexIterator(colIx);
			assertTrue(!iter.hasPrevious());

			// Forward iteration (after end)
			iter = table.indexIteratorAfter(colIx, recs[recordCnt - 1].getField(colIx));
			assertTrue(!iter.hasNext());

			// Backward iteration (before first)
			recIx = 0;
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx));
			assertTrue(!iter.hasPrevious());

			// Backward iteration (after first)
			int startIx = 0;
			recIx = findEnd(recs, startIx, colIx);
			iter = table.indexIteratorAfter(colIx, recs[startIx].getField(colIx));
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(-1, recIx);
			assertTrue(!iter.hasPrevious());

			// Forward iteration (before first - specify primary key)
			startIx = 0;
			recIx = findStart(recs, startIx, colIx);
			iter = table.indexIteratorBefore(colIx, recs[startIx].getField(colIx),
				recs[startIx].getKeyField());
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx++], rec);
			}
			assertEquals(recordCnt, recIx);

			// Backward iteration (before first - specify primary key)
			startIx = 0;
			recIx = findStart(recs, startIx, colIx);
			iter = table.indexIteratorBefore(colIx, recs[startIx].getField(colIx),
				recs[startIx].getKeyField());
			assertTrue(!iter.hasPrevious());

			// Forward iteration (before first)
			recIx = 0;
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx));
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx++], rec);
			}
			assertEquals(recordCnt, recIx);

			// Backward iteration (before first)
			recIx = 0;
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx));
			assertTrue(!iter.hasPrevious());

			// Forward iteration (end - specify primary key)
			recIx = recordCnt - 1;
			iter = table.indexIteratorAfter(colIx, recs[recIx].getField(colIx),
				recs[recIx].getKeyField());
			assertTrue(!iter.hasNext());

			// Backward iteration (end - specify primary key)
			recIx = recordCnt - 1;
			iter = table.indexIteratorAfter(colIx, recs[recIx].getField(colIx),
				recs[recIx].getKeyField());
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(-1, recIx);

			// Forward iteration (end)
			recIx = recordCnt - 1;
			iter = table.indexIteratorAfter(colIx, recs[recIx].getField(colIx));
			assertTrue(!iter.hasNext());

			// Backward iteration (end)
			recIx = recordCnt - 1;
			iter = table.indexIteratorAfter(colIx, recs[recIx].getField(colIx));
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(-1, recIx);

			// Forward iteration (start in middle - specify primary key)
			recIx = recordCnt / 2;
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx),
				recs[recIx].getKeyField());
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx++], rec);
			}
			assertEquals(recordCnt, recIx);

			// Backward iteration (start in middle - specify primary key)
			recIx = recordCnt / 2;
			iter = table.indexIteratorAfter(colIx, recs[recIx].getField(colIx),
				recs[recIx].getKeyField());
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(-1, recIx);

			// Forward iteration (from start in middle)
			recIx = findStart(recs, recordCnt / 2, colIx);
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx));
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx++], rec);
			}
			assertEquals(recordCnt, recIx);

			// Backward iteration (from start in middle)
			recIx = findStart(recs, recordCnt / 2, colIx);
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx));
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[--recIx], rec);
			}
			assertEquals(0, recIx);

			// Forward iteration (from end in middle)
			recIx = findEnd(recs, recordCnt / 2, colIx);
			iter = table.indexIteratorAfter(colIx, recs[recIx].getField(colIx));
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[++recIx], rec);
			}
			assertEquals(recordCnt - 1, recIx);

			// Reverse iteration (from end in middle)
			recIx = findEnd(recs, recordCnt / 2, colIx);
			iter = table.indexIteratorAfter(colIx, recs[recIx].getField(colIx));
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(-1, recIx);

			// Forward Range iterator
			int minIx = findStart(recs, recordCnt / 10, colIx);
			int maxIx = findEnd(recs, recordCnt / 5, colIx);
			recIx = minIx;
			iter = table.indexIterator(colIx, recs[minIx].getField(colIx),
				recs[maxIx].getField(colIx), true);
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx++], rec);
			}
			assertEquals(maxIx + 1, recIx);

			// Full forward record iterator
			recIx = 0;
			iter = table.indexIterator(colIx, null, null, true);
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx++], rec);
			}
			assertEquals(recordCnt, recIx);

			// Backward Range iterator
			minIx = findStart(recs, recordCnt / 10, colIx);
			maxIx = findEnd(recs, recordCnt / 5, colIx);
			recIx = maxIx;
			iter = table.indexIterator(colIx, recs[minIx].getField(colIx),
				recs[maxIx].getField(colIx), false);
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(minIx - 1, recIx);

			// Full reverse record iterator
			recIx = recordCnt - 1;
			iter = table.indexIterator(colIx, null, null, false);
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(-1, recIx);

			if (recs[0].getField(colIx) instanceof LongField) {

				// Forward iteration (after end)
				long k = recs[recordCnt - 1].getField(colIx).getLongValue() + 1;
				iter = table.indexIteratorBefore(colIx, new LongField(k));
				assertTrue(!iter.hasNext());

				// Forward iteration (start in middle - specify primary key)
				recIx = findStart(recs, recordCnt / 2, colIx);
				Field startValue = new LongField();
				startValue.setLongValue(recs[recIx].getField(colIx).getLongValue() - 1);
				iter = table.indexIteratorAfter(colIx, startValue);
				while (iter.hasNext()) {
					DBRecord rec = iter.next();
					assertEquals(recs[recIx++], rec);
				}
				assertEquals(recordCnt, recIx);

				// Backward iteration (start in middle)
				recIx = findEnd(recs, recordCnt / 2, colIx);
				startValue.setLongValue(recs[recIx].getField(colIx).getLongValue() + 1);
				iter = table.indexIteratorBefore(colIx, startValue);
				while (iter.hasPrevious()) {
					DBRecord rec = iter.previous();
					assertEquals(recs[recIx--], rec);
				}
				assertEquals(-1, recIx);
			}

			//*******************************************************************

			// Multi-direction check starting with forward iteration (start in middle)
			recIx = findStart(recs, recordCnt / 2, colIx);
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx));
			for (int i = 0; i < 2; i++) {
				if (iter.hasNext()) {
					DBRecord rec = iter.next();
					assertEquals(recs[recIx++], rec);
				}
			}
			--recIx;
			for (int i = 0; i < 2; i++) {
				if (iter.hasPrevious()) {
					DBRecord rec = iter.previous();
					assertEquals(recs[recIx--], rec);
				}
			}
			++recIx;
			for (int i = 0; i < 2; i++) {
				if (iter.hasNext()) {
					DBRecord rec = iter.next();
					assertEquals(recs[recIx++], rec);
				}
			}
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx++], rec);
			}
			assertEquals(recordCnt, recIx);

			// Multi-direction check starting with backward iteration (start in middle)
			recIx = findStart(recs, recordCnt / 2, colIx);
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx));
			--recIx;
			for (int i = 0; i < 2; i++) {
				if (iter.hasPrevious()) {
					DBRecord rec = iter.previous();
					assertEquals(recs[recIx--], rec);
				}
			}
			++recIx;
			for (int i = 0; i < 2; i++) {
				if (iter.hasNext()) {
					DBRecord rec = iter.next();
					assertEquals(recs[recIx++], rec);
				}
			}
			--recIx;
			for (int i = 0; i < 2; i++) {
				if (iter.hasPrevious()) {
					DBRecord rec = iter.previous();
					assertEquals(recs[recIx--], rec);
				}
			}
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(-1, recIx);

			// Multi-direction check starting with forward iteration (start at End)
			recIx = recordCnt - 1;
			iter = table.indexIteratorAfter(colIx, recs[recIx].getField(colIx));
			for (int i = 0; i < 3; i++) {
				if (iter.hasNext()) {
					DBRecord rec = iter.next();
					assertEquals(recs[recIx++], rec);
				}
			}
			assertEquals(recordCnt - 1, recIx);
			while (iter.hasPrevious()) {
				DBRecord rec = iter.previous();
				assertEquals(recs[recIx--], rec);
			}
			assertEquals(-1, recIx);

			// Multi-direction check starting with backward iteration (start at Front)
			recIx = 0;
			iter = table.indexIteratorBefore(colIx, recs[recIx].getField(colIx));
			for (int i = 0; i < 3; i++) {
				if (iter.hasPrevious()) {
					DBRecord rec = iter.previous();
					assertEquals(recs[--recIx], rec);
				}
			}
			assertEquals(0, recIx);
			while (iter.hasNext()) {
				DBRecord rec = iter.next();
				assertEquals(recs[recIx++], rec);
			}
			assertEquals(recordCnt, recIx);

			//
			// Index Field Iterator does not support variable length fields
			//
			if (lastIndex.isVariableLength()) {
				continue;// skip remain tests
			}

			// Index field iterator (all unique index values)
			minIx = 0;
			maxIx = indexFields.size() - 1;
			DBFieldIterator fiter = table.indexFieldIterator(colIx);
			int ix = minIx;
			while (fiter.hasNext()) {
				Field f = fiter.next();
				assertEquals(indexFields.get(ix++), f);
			}
			assertEquals(maxIx + 1, ix);

			// Index field iterator (forward range of unique index values)
			minIx = indexFields.size() / 10;
			maxIx = minIx * 2;
			fiter = table.indexFieldIterator(indexFields.get(minIx), indexFields.get(maxIx), true,
				colIx);
			ix = minIx;
			while (fiter.hasNext()) {
				Field f = fiter.next();
				assertEquals(indexFields.get(ix++), f);
			}
			assertEquals(maxIx + 1, ix);

			// Index field iterator (forward over all indexed fields)
			minIx = 0;
			maxIx = indexFields.size() - 1;
			fiter = table.indexFieldIterator(null, null, true, colIx);
			ix = minIx;
			assertTrue("Failed to position before min field", fiter.hasNext());
			while (fiter.hasNext()) {
				Field f = fiter.next();
				assertEquals(indexFields.get(ix++), f);
			}
			assertEquals(maxIx + 1, ix);

			// Index field iterator (reverse range of unique index values)
//			minIx = indexFields.size() / 10;
//			maxIx = minIx * 2;
			fiter = table.indexFieldIterator(indexFields.get(minIx), indexFields.get(maxIx), false,
				colIx);
			ix = maxIx;
			while (fiter.hasPrevious()) {
				Field f = fiter.previous();
				assertEquals(indexFields.get(ix--), f);
			}
			assertEquals(minIx - 1, ix);

			// Index field iterator (reverse over all indexed fields)
			minIx = 0;
			maxIx = indexFields.size() - 1;
			fiter = table.indexFieldIterator(null, null, false, colIx);
			ix = maxIx;
			assertTrue("Failed to position after max field", fiter.hasPrevious());
			while (fiter.hasPrevious()) {
				Field f = fiter.previous();
				assertEquals(indexFields.get(ix--), f);
			}
			assertEquals(-1, ix);

			// Index field iterator (forward range of unique index values)
//			minIx = indexFields.size() / 10;
//			maxIx = minIx * 2;
			startIx = (minIx + maxIx) / 2;
			fiter = table.indexFieldIterator(indexFields.get(minIx), indexFields.get(maxIx),
				indexFields.get(startIx), true, colIx);
			ix = startIx;
			while (fiter.hasNext()) {
				Field f = fiter.next();
				assertEquals(indexFields.get(ix++), f);
			}
			assertEquals(maxIx + 1, ix);

			// Index field iterator (reverse range of unique index values)
//			minIx = indexFields.size() / 10;
//			maxIx = minIx * 2;
//			startIx = (minIx + maxIx) / 2;
			fiter = table.indexFieldIterator(indexFields.get(minIx), indexFields.get(maxIx),
				indexFields.get(startIx), false, colIx);
			ix = startIx;
			while (fiter.hasPrevious()) {
				Field f = fiter.previous();
				assertEquals(indexFields.get(ix--), f);
			}
			assertEquals(minIx - 1, ix);
		}

	}
Test record iterator.

@param testStoredDB test against a stored database if true, else test against cached database
           only.
@param recordCnt number of records to test
@param keyIncrement key increment, 0 = random
@param varDataSize size of variable length data fields.
@throws IOException
Ghidra/Framework/DB/src/test/java/db/DBIndexedTableTest.java