]> source.dussan.org Git - jackcess.git/commitdiff
Add Database.newTableMetaDataIterable() which enables iterating through table names...
authorJames Ahlborn <jtahlborn@yahoo.com>
Wed, 20 Feb 2019 05:43:35 +0000 (05:43 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Wed, 20 Feb 2019 05:43:35 +0000 (05:43 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1295 f203690c-595d-4dc9-a70b-905162fa7fd2

src/changes/changes.xml
src/main/java/com/healthmarketscience/jackcess/Database.java
src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java
src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java

index c7a37e02ad17718f5c76af05a7d423a6a9a12faf..ca5133f534c9da6cdb3a6a62a3e7fec7f50f5032 100644 (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">
index 4fa874118998cc6108728b5b46565cdbf7d8eb60..7ce592827b17805c76bf01c0c4575d5bf6adcbec 100644 (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)
index 1db1c3b145c3e683621b0705aa0b3dc78d300c4d..bc3cf80ed004204a1215d7d44b6c24f2e5fb1847 100644 (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;
-    }
   }
 
   /**
index 0a33a9997d7da26cddb69da2e9a3d17cfe6ba901..2e5c35eed8d9d0432554e149cbccf2ea8c99ce25 100644 (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) {