diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2019-02-20 05:43:35 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2019-02-20 05:43:35 +0000 |
commit | 1fb85bd37a398ff94abd048bfea0a4ec9c8b86d9 (patch) | |
tree | 2b90c51a717b96dc7b103b5ddf96193e63489121 | |
parent | cdcd610a9743ed9be8c7865fdaffc5ae5bef5110 (diff) | |
download | jackcess-1fb85bd37a398ff94abd048bfea0a4ec9c8b86d9.tar.gz jackcess-1fb85bd37a398ff94abd048bfea0a4ec9c8b86d9.zip |
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
4 files changed, 144 insertions, 11 deletions
diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c7a37e0..ca5133f 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -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"> diff --git a/src/main/java/com/healthmarketscience/jackcess/Database.java b/src/main/java/com/healthmarketscience/jackcess/Database.java index 4fa8741..7ce5928 100644 --- a/src/main/java/com/healthmarketscience/jackcess/Database.java +++ b/src/main/java/com/healthmarketscience/jackcess/Database.java @@ -226,6 +226,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) * @usage _general_method_ diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java index 1db1c3b..bc3cf80 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java @@ -1051,6 +1051,20 @@ public class DatabaseImpl implements Database, DateTimeContext } @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; - } } /** diff --git a/src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java b/src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java index 0a33a99..2e5c35e 100644 --- a/src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java +++ b/src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java @@ -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) { |