Browse Source

Add Database.newTableMetaDataIterable() which enables iterating through table names without loading the entire collection into memory at once

git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1295 f203690c-595d-4dc9-a70b-905162fa7fd2
tags/jackcess-3.0.1
James Ahlborn 5 years ago
parent
commit
1fb85bd37a

+ 5
- 0
src/changes/changes.xml View File

@@ -9,6 +9,11 @@
Add ColumnFormatter utility which can apply Column "Format" property
for display of column values.
</action>
<action dev="jahlborn" type="update">
Add Database.newTableMetaDataIterable() which enables iterating
through table names without loading the entire collection into memory
at once.
</action>
</release>
<release version="3.0.0" date="2019-02-08" description="Update to Java 8">
<action dev="jahlborn" type="update">

+ 11
- 0
src/main/java/com/healthmarketscience/jackcess/Database.java View File

@@ -225,6 +225,17 @@ public interface Database extends Iterable<Table>, Closeable, Flushable
*/
public TableIterableBuilder newIterable();

/**
* @return an Iterable which returns an unmodifiable Iterator of the the
* TableMetaData for all tables in this Database.
* @throws RuntimeIOException if an IOException is thrown by one of the
* operations, the actual exception will be contained within
* @throws ConcurrentModificationException if a table is added to the
* database while an Iterator is in use.
* @usage _intermediate_method_
*/
public Iterable<TableMetaData> newTableMetaDataIterable();

/**
* @param name User table name (case-insensitive)
* @return The Table, or null if it doesn't exist (or is a system table)

+ 80
- 11
src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java View File

@@ -1050,6 +1050,20 @@ public class DatabaseImpl implements Database, DateTimeContext
return new TableIterableBuilder(this);
}

@Override
public Iterable<TableMetaData> newTableMetaDataIterable() {
return new Iterable<TableMetaData>() {
@Override
public Iterator<TableMetaData> iterator() {
try {
return _tableFinder.iterateTableMetaData();
} catch(IOException e) {
throw new RuntimeIOException(e);
}
}
};
}

@Override
public TableImpl getTable(String name) throws IOException {
return getTable(name, false);
@@ -2426,6 +2440,72 @@ public class DatabaseImpl implements Database, DateTimeContext
return false;
}

public int getNextFreeSyntheticId() throws IOException {
int maxSynthId = findMaxSyntheticId();
if(maxSynthId >= -1) {
// bummer, no more ids available
throw new IllegalStateException(withErrorContext(
"Too many database objects!"));
}
return maxSynthId + 1;
}

public Iterator<TableMetaData> iterateTableMetaData() throws IOException {
return new Iterator<TableMetaData>() {
private final Iterator<Row> _iter =
getTableNamesCursor().newIterable().setColumnNames(
SYSTEM_CATALOG_TABLE_DETAIL_COLUMNS).iterator();
private TableMetaData _next;

@Override
public boolean hasNext() {
if((_next == null) && _iter.hasNext()) {
_next = nextTableMetaData(_iter);
}
return (_next != null);
}

@Override
public TableMetaData next() {
if(!hasNext()) {
throw new NoSuchElementException();
}

TableMetaData next = _next;
_next = null;
return next;
}
};
}

private TableMetaData nextTableMetaData(Iterator<Row> detailIter) {

while(detailIter.hasNext()) {
Row row = detailIter.next();

Short type = row.getShort(CAT_COL_TYPE);
if(!isTableType(type)) {
continue;
}

int parentId = row.getInt(CAT_COL_PARENT_ID);
if(parentId != _tableParentId) {
continue;
}

String realName = row.getString(CAT_COL_NAME);
Integer pageNumber = row.getInt(CAT_COL_ID);
int flags = row.getInt(CAT_COL_FLAGS);
String linkedDbName = row.getString(CAT_COL_DATABASE);
String linkedTableName = row.getString(CAT_COL_FOREIGN_NAME);

return createTableInfo(realName, pageNumber, flags, type, linkedDbName,
linkedTableName);
}

return null;
}

protected abstract Cursor findRow(Integer parentId, String name)
throws IOException;

@@ -2438,17 +2518,6 @@ public class DatabaseImpl implements Database, DateTimeContext
throws IOException;

protected abstract int findMaxSyntheticId() throws IOException;

public int getNextFreeSyntheticId() throws IOException
{
int maxSynthId = findMaxSyntheticId();
if(maxSynthId >= -1) {
// bummer, no more ids available
throw new IllegalStateException(withErrorContext(
"Too many database objects!"));
}
return maxSynthId + 1;
}
}

/**

+ 48
- 0
src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java View File

@@ -1031,6 +1031,54 @@ public class DatabaseTest extends TestCase
assertEquals("Row[1:1][{id=37,data=<null>}]", row.toString());
}

public void testIterateTableNames() throws Exception {
for (final TestDB testDB : SUPPORTED_DBS_TEST_FOR_READ) {
final Database db = open(testDB);

Set<String> names = new HashSet<>();
int sysCount = 0;
for(TableMetaData tmd : db.newTableMetaDataIterable()) {
if(tmd.isSystem()) {
++sysCount;
continue;
}
assertFalse(tmd.isLinked());
assertNull(tmd.getLinkedTableName());
assertNull(tmd.getLinkedDbName());
names.add(tmd.getName());
}

assertTrue(sysCount > 4);
assertEquals(new HashSet<>(Arrays.asList("Table1", "Table2", "Table3",
"Table4")),
names);
}

for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.LINKED)) {
final Database db = open(testDB);

Set<String> names = new HashSet<>();
for(TableMetaData tmd : db.newTableMetaDataIterable()) {
if(tmd.isSystem()) {
continue;
}
if("Table1".equals(tmd.getName())) {
assertFalse(tmd.isLinked());
assertNull(tmd.getLinkedTableName());
assertNull(tmd.getLinkedDbName());
} else {
assertTrue(tmd.isLinked());
assertEquals("Table1", tmd.getLinkedTableName());
assertEquals("Z:\\jackcess_test\\linkeeTest.accdb", tmd.getLinkedDbName());
}
names.add(tmd.getName());
}

assertEquals(new HashSet<>(Arrays.asList("Table1", "Table2")),
names);
}
}

private static void checkRawValue(String expected, Object val)
{
if(expected != null) {

Loading…
Cancel
Save