This is an automated email from the ASF dual-hosted git repository. amanin pushed a commit to branch refactor/sql-store in repository https://gitbox.apache.org/repos/asf/sis.git
commit 01a5d2aca3328cbabb65f6ca96f74267355be805 Author: Alexis Manin <[email protected]> AuthorDate: Thu Nov 14 11:35:48 2019 +0100 doc(SQLStore): minor cleanups + javadoc. --- .../sis/internal/sql/feature/FeatureAdapter.java | 48 +++++++++++++++++++++- .../sql/feature/GeometryIdentification.java | 2 +- .../sis/internal/sql/feature/OGC06104r4.java | 2 +- .../sql/feature/QuerySpliteratorsBench.java | 35 ---------------- .../sis/internal/sql/feature/SQLCloseable.java | 5 ++- .../sis/internal/sql/feature/SQLQueryAdapter.java | 13 +++++- .../org/apache/sis/internal/sql/feature/Table.java | 3 +- 7 files changed, 66 insertions(+), 42 deletions(-) diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/FeatureAdapter.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/FeatureAdapter.java index d9a2752..9f67832 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/FeatureAdapter.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/FeatureAdapter.java @@ -13,12 +13,27 @@ import org.opengis.feature.FeatureType; import static org.apache.sis.util.ArgumentChecks.ensureNonNull; +/** + * Convert data from a specific query into Feature entities. This object can be prepared once for a specific statement, + * and reused each time it is executed. + * + * @implNote For now, only attributes (values) are converted. Associations are delegated to the specific table reading + * case, through {@link Features} class. + * + * This object has an initialization phase, to prepare it for a specific ResultSet, through {@link #prepare(Connection)} + * method. It allows mappers to fetch specific information from the database when needed. + */ class FeatureAdapter { final FeatureType type; private final List<PropertyMapper> attributeMappers; + /** + * Creates an adapter producing features of the given type, and populating its attributes with input mappers. + * @param type The data type to produce as output. Cannot be null. + * @param attributeMappers Attribute mappers to use to decode SQL values. Mandatory (can be empty, though) + */ FeatureAdapter(FeatureType type, List<PropertyMapper> attributeMappers) { ensureNonNull("Target feature type", type); ensureNonNull("Attribute mappers", attributeMappers); @@ -26,6 +41,12 @@ class FeatureAdapter { this.attributeMappers = Collections.unmodifiableList(new ArrayList<>(attributeMappers)); } + /** + * Get a worker for a specific connection. Note that any number of result sets can be parsed with this, as long as + * the connection is open. + * @param target Connection usable by the mapper all along its lifecycle. + * @return A mapper ready-to-read SQL result set. + */ ResultSetAdapter prepare(final Connection target) { final List<ReadyMapper> rtu = attributeMappers.stream() .map(mapper -> mapper.prepare(target)) @@ -33,6 +54,10 @@ class FeatureAdapter { return new ResultSetAdapter(rtu); } + /** + * Specialization of {@link FeatureAdapter} as a short-live object, able to use a database connection to load third- + * party data. + */ final class ResultSetAdapter { final List<ReadyMapper> mappers; @@ -40,6 +65,15 @@ class FeatureAdapter { this.mappers = mappers; } + /** + * Read current row as a Feature. For repeated calls, please consider using {@link #prefetch(int, ResultSet)} + * instead. + * + * @param cursor The result set containing query result. It must be positioned on the row you want to read. It + * is also your responsability to move on cursor to another row after this call. + * @return A feature holding values of the current row of input result set. Never null. + * @throws SQLException If an error occurs while querying a column value. + */ Feature read(final ResultSet cursor) throws SQLException { final Feature result = readAttributes(cursor); addImports(result, cursor); @@ -53,7 +87,19 @@ class FeatureAdapter { return result; } - //final SQLBiFunction<ResultSet, Integer, ?>[] adapters; + /** + * Load a number of rows in one go. Beware, behavior of this method is different from {@link #read(ResultSet)}, + * as it WON'T read currentl row. It wil start by moving to next row, and then read sequentially all rows until + * given count is done, or the given result set is over. + * + * @param size Maximum number of elements to read from given result set. If negative or zero, this function is a + * no-op. + * @param cursor Result set to extract data from. To read first entry of it, you must NOT have called {@link ResultSet#next()} + * on it. + * @return A modifiable list of read elements. Never null, can be empty. It can contain less elements than asked + * but never more. + * @throws SQLException If extracting values from input result set fails. + */ List<Feature> prefetch(final int size, final ResultSet cursor) throws SQLException { // TODO: optimize by resolving import associations by batch import fetching. final ArrayList<Feature> features = new ArrayList<>(size); diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/GeometryIdentification.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/GeometryIdentification.java index 5e97236..9a4e475 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/GeometryIdentification.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/GeometryIdentification.java @@ -110,7 +110,7 @@ class GeometryIdentification implements SQLCloseable { final String name = cursor.getString(1); final int dimension = cursor.getInt(2); final int pgSrid = cursor.getInt(3); - final String type = cursor.getString(4); + final String type = typeIncluded ? cursor.getString(4) : null; // Note: we make a query per entry, which could impact performance. However, 99% of defined tables // will have only one geometry column. Moreover, even with more than one, with prepared statement, the // performance impact should stay low. diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/OGC06104r4.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/OGC06104r4.java index 480de0c..c7115e7 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/OGC06104r4.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/OGC06104r4.java @@ -40,7 +40,7 @@ final class OGC06104r4 implements DialectMapping { private OGC06104r4(final OGC06104r4.Spi spi, Connection c) throws SQLException { this.spi = spi; sessionCache = new Cache<>(7, 0, true); - this.identifyGeometries = new GeometryIdentification(c, "geometry_columns", "f_geometry_column", "type", sessionCache); + this.identifyGeometries = new GeometryIdentification(c, sessionCache); this.library = Geometries.implementation(null); } diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/QuerySpliteratorsBench.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/QuerySpliteratorsBench.java index bb519d9..0033c41 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/QuerySpliteratorsBench.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/QuerySpliteratorsBench.java @@ -108,42 +108,7 @@ public class QuerySpliteratorsBench { final int sum = input.fs.features(input.parallel).mapToInt(f -> 1).sum(); if (sum != input.numRows) throw new AssertionError("..." + sum + "..." + "WTF ?!"); } -/* - @Test - public void benchmark() throws Exception { - System.out.println("COMMON POOL: "+ ForkJoinPool.getCommonPoolParallelism()); - final DatabaseInput db = new DatabaseInput(); - db.numRows = 100000; - db.parallel = true; - - long start = System.nanoTime(); - db.setup(); - System.out.println("Insertion time: "+((System.nanoTime()-start)/1e6)+" ms"); - - // warmup - for (int i = 0 ; i < 5 ; i++) { - test(db); - test(db); - } - - // go - long prefetch = 0, noprefetch = 0; - for (int i = 0 ; i < 100 ; i++) { - start = System.nanoTime(); - test(db); - prefetch += System.nanoTime()-start; - start = System.nanoTime(); - test(db); - noprefetch += System.nanoTime()-start; - } - - System.out.println(String.format( - "Performances:%nP: %d%nI: %d", - (long) (prefetch / 1e7), (long) (noprefetch / 1e8) - )); - } -*/ public static void main(String... args) throws Exception { org.openjdk.jmh.Main.main(args); } diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLCloseable.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLCloseable.java index 439b4f1..c027c33 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLCloseable.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLCloseable.java @@ -2,7 +2,10 @@ package org.apache.sis.internal.sql.feature; import java.sql.SQLException; -public interface SQLCloseable extends AutoCloseable { +/** + * Specialisation of {@link AutoCloseable standard closeable objects} for SQL related resources. + */ +interface SQLCloseable extends AutoCloseable { @Override void close() throws SQLException; } diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLQueryAdapter.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLQueryAdapter.java index 2932c98..083575b 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLQueryAdapter.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/SQLQueryAdapter.java @@ -13,6 +13,9 @@ import org.apache.sis.internal.storage.SubsetAdapter; import org.apache.sis.internal.storage.query.SimpleQuery; import org.apache.sis.storage.FeatureSet; +/** + * + */ abstract class SQLQueryAdapter implements SubsetAdapter.AdapterBuilder { private ColumnRef[] columns; @@ -116,7 +119,15 @@ abstract class SQLQueryAdapter implements SubsetAdapter.AdapterBuilder { } } - public static Supplier<ANSIInterpreter> forDialect(final Dialect dialect) { + /** + * Give back a filter/expression interpreter for a given database dialect. + * TODO: unify with {@link DialectMapping}. + * + * @param dialect Database dialect that must be produced by the interpreter. If null, {@link Dialect#ANSI} is used + * as a fallback. + * @return A function able to give a fresh interpreter on demaind. + */ + static Supplier<ANSIInterpreter> forDialect(final Dialect dialect) { switch (dialect) { case POSTGRESQL: return () -> new PostGISInterpreter(); default: return () -> new ANSIInterpreter(); diff --git a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java index 22c9aba..9669c29 100644 --- a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java +++ b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Table.java @@ -46,7 +46,6 @@ import org.apache.sis.storage.DataStoreException; import org.apache.sis.storage.FeatureSet; import org.apache.sis.storage.InternalDataStoreException; import org.apache.sis.storage.Query; -import org.apache.sis.storage.UnsupportedQueryException; import org.apache.sis.util.Debug; import org.apache.sis.util.collection.TreeTable; import org.apache.sis.util.collection.WeakValueHashMap; @@ -206,7 +205,7 @@ final class Table extends AbstractFeatureSet { } @Override - public FeatureSet subset(Query query) throws UnsupportedQueryException, DataStoreException { + public FeatureSet subset(Query query) throws DataStoreException { if (query instanceof SimpleQuery) { final SubsetAdapter subsetAdapter = new SubsetAdapter(fs -> new SQLQueryAdapter.Table(this)); return subsetAdapter.subset(this, (SimpleQuery) query);
