This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-3.1 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 0704b92b5ebd2f50365b8b32a7eaf2ac2838e70b Merge: 61ff831a8e ece63c46f5 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Tue Apr 1 18:20:10 2025 +0200 Merge branch 'geoapi-4.0' into geoapi-3.1. Contains bug fixes in SQLStore. .../org/apache/sis/feature/AbstractOperation.java | 18 + .../org/apache/sis/feature/EnvelopeOperation.java | 3 +- .../apache/sis/feature/ExpressionOperation.java | 3 +- .../sis/feature/GroupAsPolylineOperation.java | 3 +- .../main/org/apache/sis/feature/LinkOperation.java | 3 +- .../apache/sis/feature/StringJoinOperation.java | 3 +- .../org/apache/sis/feature/internal/Resources.java | 5 + .../sis/feature/internal/Resources.properties | 1 + .../sis/feature/internal/Resources_fr.properties | 1 + .../sis/feature/privy/AttributeConvention.java | 6 + .../apache/sis/feature/privy/FeatureUtilities.java | 98 ------ .../apache/sis/filter/BinaryGeometryFilter.java | 2 +- .../main/org/apache/sis/filter/LeafExpression.java | 2 +- .../main/org/apache/sis/filter/internal/Node.java | 24 +- .../sis/filter/privy/ListingPropertyVisitor.java | 137 ++++++++ .../org/apache/sis/filter/privy/WarningEvent.java | 128 +++++++ .../geometry/wrapper/jts/GeometryTransform.java | 10 +- .../org/apache/sis/geometry/wrapper/jts/JTS.java | 20 +- .../main/org/apache/sis/image/ImageProcessor.java | 4 +- .../sis/geometry/wrapper/esri/FactoryTest.java | 8 +- .../apache/sis/geometry/wrapper/jts/JTSTest.java | 2 +- .../org/apache/sis/metadata/sql/privy/Dialect.java | 52 ++- .../apache/sis/metadata/sql/privy/SQLBuilder.java | 116 +++++-- .../sis/metadata/sql/privy/SQLUtilities.java | 43 ++- .../org/apache/sis/metadata/sql/privy/Syntax.java | 70 +++- .../org/apache/sis/temporal/LenientDateFormat.java | 6 +- .../main/org/apache/sis/temporal/TimeMethods.java | 6 +- .../sis/metadata/sql/privy/SQLBuilderTest.java | 97 ++++++ .../sis/metadata/sql/privy/SQLUtilitiesTest.java | 13 +- .../main/org/apache/sis/openoffice/CalcAddins.java | 2 +- .../coverage/MultiResolutionCoverageLoader.java | 2 +- .../apache/sis/io/wkt/GeodeticObjectParser.java | 21 +- .../sis/referencing/operation/matrix/Matrices.java | 62 +++- .../referencing/operation/matrix/MatricesTest.java | 16 + .../apache/sis/storage/landsat/MetadataReader.java | 16 +- .../geotiff/reader/GridGeometryBuilder.java | 13 +- .../sis/storage/geotiff/writer/GeoEncoder.java | 85 ++++- .../sis/storage/netcdf/base/GridMapping.java | 2 +- .../sis/storage/netcdf/ucar/DecoderWrapper.java | 3 +- .../main/module-info.java | 1 + .../org/apache/sis/storage/sql/DataAccess.java | 2 + .../main/org/apache/sis/storage/sql/SQLStore.java | 43 ++- .../org/apache/sis/storage/sql/duckdb/DuckDB.java | 88 +++++ .../{postgis => duckdb}/ExtendedClauseWriter.java | 14 +- .../sis/storage/sql/duckdb/package-info.java | 60 ++++ .../apache/sis/storage/sql/feature/Analyzer.java | 112 ++++-- .../org/apache/sis/storage/sql/feature/Column.java | 67 +++- .../apache/sis/storage/sql/feature/Database.java | 191 ++++++++-- .../sis/storage/sql/feature/FeatureAdapter.java | 8 +- .../sis/storage/sql/feature/FeatureAnalyzer.java | 12 +- .../sis/storage/sql/feature/FeatureIterator.java | 87 ++++- .../sis/storage/sql/feature/FeatureStream.java | 91 ++++- .../sis/storage/sql/feature/GeometryEncoding.java | 25 +- .../sis/storage/sql/feature/GeometryGetter.java | 103 ++++-- .../sis/storage/sql/feature/InfoStatements.java | 104 ++++-- .../sis/storage/sql/feature/QueryAnalyzer.java | 4 +- .../apache/sis/storage/sql/feature/Relation.java | 48 ++- .../apache/sis/storage/sql/feature/Resources.java | 15 + .../sis/storage/sql/feature/Resources.properties | 3 + .../storage/sql/feature/Resources_fr.properties | 5 +- .../sis/storage/sql/feature/SelectionClause.java | 250 +++++++++++++- .../storage/sql/feature/SelectionClauseWriter.java | 38 +- .../sis/storage/sql/feature/SpatialSchema.java | 73 +++- .../org/apache/sis/storage/sql/feature/Table.java | 148 ++++++-- .../sis/storage/sql/feature/TableAnalyzer.java | 61 ++-- .../sis/storage/sql/feature/TableReference.java | 2 +- .../storage/sql/postgis/ExtendedClauseWriter.java | 5 + .../sis/storage/sql/postgis/ExtendedInfo.java | 32 +- .../sis/storage/sql/postgis/ExtentEstimator.java | 2 +- .../apache/sis/storage/sql/postgis/Postgres.java | 22 +- .../org/apache/sis/storage/sql/SQLStoreTest.java | 22 +- .../storage/sql/feature/GeometryGetterTest.java | 3 +- .../sis/storage/sql/postgis/PostgresTest.java | 123 ++++++- .../sis/storage/sql/postgis/RasterReaderTest.java | 5 +- .../sis/storage/sql/postgis/RasterWriterTest.java | 4 +- .../sis/storage/sql/postgis/SpatialFeatures.sql | 8 + .../apache/sis/io/stream/InternalOptionKey.java | 2 +- .../main/org/apache/sis/storage/FeatureQuery.java | 237 +++++-------- .../main/org/apache/sis/storage/FeatureSubset.java | 37 +- .../org/apache/sis/storage/StorageConnector.java | 28 +- .../apache/sis/storage/base/FeatureProjection.java | 383 +++++++++++++++++++++ .../apache/sis/storage/base/MetadataBuilder.java | 113 ++++-- .../main/org/apache/sis/storage/csv/Store.java | 2 +- .../org/apache/sis/storage/image/FormatFilter.java | 4 +- .../org/apache/sis/storage/image/FormatFinder.java | 67 +--- .../apache/sis/storage/image/MultiImageStore.java | 2 +- .../apache/sis/storage/image/SingleImageStore.java | 2 +- .../apache/sis/storage/image/WorldFileStore.java | 31 +- .../apache/sis/storage/image/WritableStore.java | 2 +- .../org/apache/sis/storage/wkt/StoreFormat.java | 2 +- .../org/apache/sis/storage/FeatureQueryTest.java | 24 ++ .../sis/storage/image/SelfConsistencyTest.java | 2 +- .../sis/storage/image/WorldFileStoreTest.java | 13 +- .../services/org.apache.sis.util.ObjectConverter | 11 + .../org/apache/sis/converter/StringConverter.java | 2 +- .../main/org/apache/sis/setup/GeometryLibrary.java | 37 +- .../org/apache/sis/util/collection/WeakEntry.java | 2 +- .../apache/sis/util/collection/WeakHashSet.java | 1 + .../org/apache/sis/util/privy/CollectionsExt.java | 18 + .../org/apache/sis/util/resources/Vocabulary.java | 5 + .../sis/util/resources/Vocabulary.properties | 1 + .../sis/util/resources/Vocabulary_fr.properties | 1 + .../apache/sis/storage/geoheif/GeoHeifStore.java | 2 +- .../storage/shapefile/ListingPropertyVisitor.java | 82 ----- .../sis/storage/shapefile/ShapefileStore.java | 7 +- .../apache/sis/storage/shapefile/dbf/DBFField.java | 11 +- .../apache/sis/gui/coverage/CoverageCanvas.java | 68 +++- .../gui/coverage/MultiResolutionImageLoader.java | 2 +- .../main/org/apache/sis/gui/map/MapCanvas.java | 6 +- .../main/org/apache/sis/gui/map/package-info.java | 2 +- .../org/apache/sis/storage/gdal/FieldAccessor.java | 3 +- .../org/apache/sis/storage/gdal/GDALStore.java | 4 +- 112 files changed, 3197 insertions(+), 1006 deletions(-) diff --cc endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java index fff5aee952,9da2a6ded1..473d878140 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java @@@ -2159,8 -2155,12 +2158,12 @@@ class GeodeticObjectParser extends Math cs = parseCoordinateSystem(element, WKTKeywords.Cartesian, 2, isWKT1, csUnit, geoCRS.getDatum()); final Map<String,?> properties = parseMetadataAndClose(element, name, conversion); if (cs instanceof CartesianCS) { + /* + * TODO: if the CartesianCS is three-dimensional, we need to ensure that the base CRS is also + * three-dimensional. We could do that by parsing the CS before to invoke `parseGeodeticCRS`. + */ final CRSFactory crsFactory = factories.getCRSFactory(); - return crsFactory.createProjectedCRS(properties, (GeodeticCRS) geoCRS, conversion, (CartesianCS) cs); + return crsFactory.createProjectedCRS(properties, (GeographicCRS) geoCRS, conversion, (CartesianCS) cs); } } catch (FactoryException exception) { throw element.parseFailed(exception); diff --cc endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SelectionClause.java index 819d204b07,aa0d7a92ab..72e55881ba --- a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SelectionClause.java +++ b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SelectionClause.java @@@ -170,4 -308,90 +308,90 @@@ public final class SelectionClause exte } return true; } + + /** + * Returns whether an error occurred while writing the <abbr>SQL</abbr> statement. + * If this method returns {@code true}, then the caller should truncate the SQL to + * the last length which was known to be valid and fallback on Java code for the rest. + */ + final boolean isInvalid() { + return isInvalid; + } + + /** + * Declares the SQL as invalid. It does not means that the whole SQL needs to be discarded. + * The SQL may be truncated to the last point where it was considered valid. + */ + final void invalidate() { + isInvalid = true; + } + + /** + * Returns the localized resources for warnings and error messages. + */ + private Resources resources() { + return Resources.forLocale(table.database.listeners.getLocale()); + } + + /** + * Sets the logger, class and method names of the given record, then logs it. + * This method declares {@link FeatureSet#features(boolean)} as the public source of the log. + * + * @param record the record to configure and log. + */ + private void log(final LogRecord record) { + record.setSourceClassName(FeatureSet.class.getName()); + record.setSourceMethodName("features"); + record.setLoggerName(Modules.SQL); + table.database.listeners.warning(record); + } + + /** + * Invoked when a warning occurred during operations on filters or expressions. + * + * @param event the warning. + */ + @Override + public void accept(final WarningEvent event) { + final LogRecord record = resources().getLogRecord( + Level.WARNING, + Resources.Keys.IncompatibleLiteralCRS_2, - event.getOperatorType().flatMap(CodeList::identifier).orElse("?"), ++ event.getOperatorType().map(CodeList::identifier).orElse("?"), + event.getParameter(ValueReference.class).map(ValueReference<?,?>::getXPath).orElse("?")); + record.setThrown(event.exception); + log(record); + } + + /** + * Returns the <abbr>SQL</abbr> fragment built by this {@code SelectionClause}. + * This method completes the information that we deferred until a connection is established. + * + * @param spatialInformation a cache of statements for fetching spatial information, or {@code null}. + * @return the <abbr>SQL</abbr> fragment, or {@code null} if there is no {@code WHERE} clause to add. + * @throws Exception if an SQL error, parsing error or other error occurred. + */ + final String query(final Connection connection, InfoStatements spatialInformation) throws Exception { + if (isEmpty()) { + return null; + } + boolean close = false; + for (int i = parameters.size(); --i >= 0;) { + if (spatialInformation == null) { + spatialInformation = table.database.createInfoStatements(connection); + close = true; + } + final var entry = parameters.get(i); + final int index = entry.getKey(); + final int srid = spatialInformation.findSRID(entry.getValue()); + buffer.replace(index, index + 1, Integer.toString(srid)); + } + if (close) { + /* + * We could put this in a `finally` block, but this method is already invoked + * in a context where the caller will close the connection in case of failure. + */ + spatialInformation.close(); + } + return buffer.toString(); + } } diff --cc endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java index ef6d83a2bb,41a6938b8d..2d26e160c4 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java @@@ -1416,8 -1436,7 +1435,9 @@@ public class MetadataBuilder public final void addOtherCitationDetails(final CharSequence details) { final InternationalString i18n = trim(details); if (i18n != null) { - addIfNotPresent(citation().getOtherCitationDetails(), i18n); ++ @SuppressWarnings("LocalVariableHidesMemberVariable") + final DefaultCitation citation = citation(); + citation.setOtherCitationDetails(append(citation.getOtherCitationDetails(), i18n)); } } @@@ -3105,11 -3134,31 +3137,32 @@@ } /** - * Adds a note about which reader is used. This method should not be invoked before - * the {@linkplain #addFormatName format name} has been set. Storage location is: + * Adds other information about the format. Apache SIS currently uses this + * location for specifying which software was used for reading the data. + * Storage location is: + * + * <ul> + * <li>{@code metadata/identificationInfo/resourceFormat/formatSpecificationCitation/otherCitationDetails}</li> + * </ul> + * + * @param details other details about the format, or {@code null} for no-operation. + * + * @see #addOtherCitationDetails(CharSequence) + */ + public final void addFormatCitationDetails(final CharSequence details) { + final InternationalString i18n = trim(details); + if (i18n != null) { - addIfNotPresent(getFormatCitation().getOtherCitationDetails(), i18n); ++ final DefaultCitation c = getFormatCitation(); ++ c.setOtherCitationDetails(append(c.getOtherCitationDetails(), i18n)); + } + } + + /** + * Adds a note about which reader is used. Apache SIS currently stores this information as other format + * citation details, but this location may change in a SIS future version if we find a better location. + * Storage location is as below, wrapped in a "Read by {0} version {1}" text: * * <ul> - * <li>{@code metadata/identificationInfo/resourceFormat/formatSpecificationCitation/identifier}</li> * <li>{@code metadata/identificationInfo/resourceFormat/formatSpecificationCitation/otherCitationDetails}</li> * </ul> *