git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1295 f203690c-595d-4dc9-a70b-905162fa7fd2tags/jackcess-3.0.1
@@ -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"> |
@@ -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) |
@@ -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; | |||
} | |||
} | |||
/** |
@@ -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) { |