protected CompletableFuture<Schema> tables(CompletableFuture<Map<String, Class<?>>> sqlTypeMapping, Dbms dbms, Schema schema, ProgressMeasure progressListener) {
        requireNonNulls(sqlTypeMapping, dbms, schema, progressListener);
        
        // If the wrapped task has already been cancelled, there is no point in going on.
        if (sqlTypeMapping.isCancelled()) {
            return CompletableFuture.completedFuture(null);
        }

        final String action = actionName(schema);
        LOGGER.info(action);
        progressListener.setCurrentAction(action);

        final long begin = System.currentTimeMillis();
        try (final Connection connection = getConnection(dbms)) {
            try (final ResultSet rsTable = connection.getMetaData().getTables(
                    jdbcCatalogLookupName(schema),
                    jdbcSchemaLookupName(schema),
                    null, new String[] {"TABLE", "VIEW"})) {

                readTables(schema, rsTable);
            }
        } catch (final SQLException sqle) {
            throw new SpeedmentException(sqle);
        }
        final long duration = System.currentTimeMillis() - begin;
        timers.computeIfAbsent(Table.class, unused -> new AtomicLong()).addAndGet(duration);

        final AtomicInteger cnt = new AtomicInteger();
        final double noTables = schema.tables().count();

        return CompletableFuture.allOf(
            schema.tables().map(table -> sqlTypeMapping.thenAcceptAsync(mapping -> {
                try (final Connection connection = getConnection(dbms)) {
                    progressListener.setCurrentAction(actionName(table));
                    columns(connection, mapping, table, progressListener);
                    indexes(connection, table, progressListener);
                    foreignKeys(connection, table, progressListener);
                    primaryKeyColumns(connection, table, progressListener);
                    progressListener.setProgress(cnt.incrementAndGet() / noTables);
                } catch (final SQLException ex) {
                    throw new SpeedmentException(ex);
                }
            })).toArray(CompletableFuture[]::new)
        ).thenApplyAsync(v -> schema);
    }
@author  Emil Forslund
@author  Per Minborg
@since   3.0.0
runtime-parent/runtime-core/src/main/java/com/speedment/runtime/core/abstracts/AbstractDbmsMetadataHandler.java