This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 8abf1fdeeb Add explicit `ST_AsBinary` or `ST_AsText` functions when 
requesting a geometry.
8abf1fdeeb is described below

commit 8abf1fdeeb7749124c01f7b447b9fa4fa4f70e2a
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Tue Apr 15 15:31:45 2025 +0200

    Add explicit `ST_AsBinary` or `ST_AsText` functions when requesting a 
geometry.
---
 .../org/apache/sis/storage/sql/feature/Column.java | 43 ++++++++--
 .../apache/sis/storage/sql/feature/Database.java   | 48 +++++++++--
 .../sis/storage/sql/feature/FeatureAdapter.java    | 20 ++++-
 .../sis/storage/sql/feature/GeometryEncoding.java  | 93 +++++++++++++++++++++-
 .../sis/storage/sql/feature/InfoStatements.java    |  2 +-
 .../sis/storage/sql/feature/QueryAnalyzer.java     |  6 ++
 .../storage/sql/feature/SelectionClauseWriter.java |  6 +-
 .../sis/storage/sql/feature/TableAnalyzer.java     |  4 +
 .../sis/storage/sql/feature/ValueGetter.java       |  2 +-
 .../apache/sis/storage/sql/postgis/Postgres.java   |  4 +-
 10 files changed, 207 insertions(+), 21 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Column.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Column.java
index e4a2393e17..1d23b834c0 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Column.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Column.java
@@ -27,7 +27,6 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.metadata.sql.privy.Reflection;
 import org.apache.sis.metadata.sql.privy.SQLUtilities;
 import org.apache.sis.geometry.wrapper.GeometryType;
-import org.apache.sis.util.Localized;
 import org.apache.sis.util.privy.Strings;
 import org.apache.sis.storage.DataStoreContentException;
 import org.apache.sis.feature.builder.AttributeTypeBuilder;
@@ -116,6 +115,13 @@ public final class Column implements Cloneable {
      */
     private GeometryType geometryType;
 
+    /**
+     * Whether the geometries are encoded in <abbr>WKT</abbr> rather than 
<abbr>WKB</abbr>.
+     *
+     * @see #getGeometryEncoding()
+     */
+    private boolean geometryAsText;
+
     /**
      * If this column is a geometry or raster column, the Coordinate Reference 
System (CRS). Otherwise {@code null}.
      * This is determined from the geometry Spatial Reference Identifier 
(SRID).
@@ -218,11 +224,11 @@ public final class Column implements Cloneable {
      * It can also be invoked during the inspection of {@code 
"GEOGRAPHY_COLUMNS"} or {@code "RASTER_COLUMNS"}
      * tables, which are PostGIS extensions. In the raster case, the geometry 
{@code type} argument shall be null.
      *
-     * @param  caller  provider of the locale for error message, if any.
-     * @param  type    the type of values in the column, or {@code null} if 
not geometric.
-     * @param  crs     the Coordinate Reference System (CRS), or {@code null} 
if unknown.
+     * @param  database  the database for which to analyze the tables.
+     * @param  type      the type of values in the column, or {@code null} if 
not geometric.
+     * @param  crs       the Coordinate Reference System (CRS), or {@code 
null} if unknown.
      */
-    final void makeSpatial(final Localized caller, final GeometryType type, 
final CoordinateReferenceSystem crs)
+    final void makeSpatial(final Database<?> database, final GeometryType 
type, final CoordinateReferenceSystem crs)
             throws DataStoreContentException
     {
         final String property;
@@ -233,12 +239,28 @@ public final class Column implements Cloneable {
         } else {
             geometryType = type;
             defaultCRS = crs;
+            geometryAsText = (database.getGeometryEncoding(this) == 
GeometryEncoding.WKT);
             return;
         }
-        throw new 
DataStoreContentException(Errors.forLocale(caller.getLocale())
+        throw new 
DataStoreContentException(Errors.forLocale(database.listeners.getLocale())
                         .getString(Errors.Keys.ValueAlreadyDefined_1, 
property));
     }
 
+    /**
+     * Tries to parses the geometry type from the field type.
+     * This is used as a fallback when no geometry column is found or can be 
used.
+     *
+     * @param  database  the database for which to analyze the tables.
+     */
+    final void tryMakeSpatial(final Database<?> database) {
+        try {
+            geometryType = GeometryType.forName(typeName);
+            geometryAsText = (database.getGeometryEncoding(this) == 
GeometryEncoding.WKT);
+        } catch (IllegalArgumentException e) {
+            // Ignore.
+        }
+    }
+
     /**
      * Returns a column identical to this column except for the property name.
      * This method does not modify this column, but may return {@code this} if
@@ -287,6 +309,15 @@ public final class Column implements Cloneable {
         return Optional.ofNullable(geometryType);
     }
 
+    /**
+     * Returns whether the geometries are encoded in <abbr>WKT</abbr> rather 
than <abbr>WKB</abbr>.
+     *
+     * @return the encoding used for geometries.
+     */
+    public final GeometryEncoding getGeometryEncoding() {
+        return geometryAsText ? GeometryEncoding.WKT : GeometryEncoding.WKB;
+    }
+
     /**
      * If this column is a geometry or raster column, returns the default 
coordinate reference system.
      * Otherwise returns empty. The CRS may also be empty even for a geometry 
column if it is unspecified.
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Database.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Database.java
index 752c2da858..515e6a0737 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Database.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Database.java
@@ -19,6 +19,7 @@ package org.apache.sis.storage.sql.feature;
 import java.util.Map;
 import java.util.List;
 import java.util.EnumSet;
+import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.WeakHashMap;
 import java.util.LinkedHashMap;
@@ -129,6 +130,15 @@ public class Database<G> extends Syntax  {
      */
     final Geometries<G> geomLibrary;
 
+    /**
+     * The functions to use for fetching a geometry from a column. Initialized 
(indirectly) the first time
+     * that {@link #getFilterToSupportedSQL()} is invoked and should not be 
modified after that point.
+     *
+     * @see #setGeometryEncodingFunctions(String[][])
+     * @see #getGeometryEncodingFunction(Column)
+     */
+    private final EnumMap<GeometryEncoding, String> geometryReaders;
+
     /**
      * Whether {@link Types#TINYINT} is a signed integer. Both conventions 
(-128 … 127 range and 0 … 255 range)
      * are found on the web. If unspecified, we conservatively assume unsigned 
bytes.
@@ -313,6 +323,7 @@ public class Database<G> extends Syntax  {
         supportsSchemas    = metadata.supportsSchemasInDataManipulation();
         supportsJavaTime   = dialect.supportsJavaTime();
         crsEncodings       = EnumSet.noneOf(CRSEncoding.class);
+        geometryReaders    = new EnumMap<>(GeometryEncoding.class);
         transactionLocks   = dialect.supportsConcurrency() ? null : locks;
         softwareVersions   = new LinkedHashMap<>(4);
         final String product = 
Strings.trimOrNull(metadata.getDatabaseProductName());
@@ -437,6 +448,14 @@ public class Database<G> extends Syntax  {
         return ignoredTables;
     }
 
+    /**
+     * Helper method for checking if catalog or schema names are consistent.
+     * If an previous (old) name existed, the new name should be the same.
+     */
+    private static boolean consistent(final String oldName, final String 
newName) {
+        return (oldName == null) || oldName.equals(newName);
+    }
+
     /**
      * Creates a model about the specified tables in the database.
      * This method shall be invoked exactly once after {@code Database} 
construction.
@@ -486,11 +505,15 @@ public class Database<G> extends Syntax  {
     }
 
     /**
-     * Helper method for checking if catalog or schema names are consistent.
-     * If an previous (old) name existed, the new name should be the same.
+     * Sets the preferred functions for fetching or storing geometries.
+     * This method is invoked indirectly by {@link #analyze analyze(…)}.
+     *
+     * @param  accessors  the array created by {@link 
GeometryEncoding#initial()}.
+     *
+     * @see #getGeometryEncodingFunction(Column)
      */
-    private static boolean consistent(final String oldName, final String 
newName) {
-        return (oldName == null) || oldName.equals(newName);
+    final void setGeometryEncodingFunctions(final String[][] accessors) {
+        GeometryEncoding.store(accessors, geometryReaders);
     }
 
     /**
@@ -645,7 +668,7 @@ public class Database<G> extends Syntax  {
         final GeometryType type = 
columnDefinition.getGeometryType().orElse(GeometryType.GEOMETRY);
         final Class<? extends G> geometryClass = 
geomLibrary.getGeometryClass(type).asSubclass(geomLibrary.rootClass);
         return new GeometryGetter<>(geomLibrary, geometryClass, 
columnDefinition.getDefaultCRS().orElse(null),
-                                    getBinaryEncoding(columnDefinition), 
getGeometryEncoding(columnDefinition));
+                                    getBinaryEncoding(columnDefinition), 
columnDefinition.getGeometryEncoding());
     }
 
     /**
@@ -828,6 +851,8 @@ public class Database<G> extends Syntax  {
     /**
      * Returns the converter from filters/expressions to the {@code WHERE} 
part of SQL statement
      * without the functions that are unsupported by the database software.
+     *
+     * A side effect of this method is to initialize {@link #geometryReaders}.
      */
     final synchronized SelectionClauseWriter getFilterToSupportedSQL() {
         if (filterToSQL == null) {
@@ -836,6 +861,19 @@ public class Database<G> extends Syntax  {
         return filterToSQL;
     }
 
+    /**
+     * Returns the function to use fo reading or writing a geometry in the 
database.
+     *
+     * @todo Add a parameter for specifying whether this is for a read or 
write operation.
+     *
+     * @param  column  the column of the geometry to read or write.
+     * @return the function to use, or {@code null} if none.
+     */
+    final String getGeometryEncodingFunction(final Column column) {
+        getFilterToSupportedSQL();      // Force initialization of 
`geometryReaders` if not already done.
+        return geometryReaders.get(column.getGeometryEncoding());
+    }
+
     /**
      * Prepares a cache of statements about spatial information using the 
given connection.
      * Each statement in the returned object will be created only when first 
needed.
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureAdapter.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureAdapter.java
index 7cb4b6e8f7..5aedba02ed 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureAdapter.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureAdapter.java
@@ -170,7 +170,11 @@ final class FeatureAdapter {
          */
         final var sql = new 
SQLBuilder(table.database).append(SQLBuilder.SELECT);
         for (final Column column : attributes) {
-            appendColumn(sql, column.label, columnIndices);
+            String function = null;
+            if (column.getGeometryType().isPresent()) {
+                function = table.database.getGeometryEncodingFunction(column);
+            }
+            appendColumn(sql, table.database, function, column.label, 
columnIndices);
         }
         /*
          * Collect information about associations in local arrays before to 
assign
@@ -270,15 +274,23 @@ final class FeatureAdapter {
      * An exception is thrown if the column has already been added (should 
never happen).
      *
      * @param  sql            the SQL statement where to add column 
identifiers after the {@code SELECT} clause.
+     * @param  database       the database. May be {@code null} if {@code 
function} is null.
+     * @param  function       a function for which the column is an argument, 
or {@code null} if none.
      * @param  column         name of the column to add.
      * @param  columnIndices  map where to add the mapping from column name to 
1-based column index.
      */
-    private static int appendColumn(final SQLBuilder sql, final String column,
-            final Map<String,Integer> columnIndices) throws 
InternalDataStoreException
+    private static int appendColumn(final SQLBuilder sql, final Database<?> 
database, final String function,
+            final String column, final Map<String,Integer> columnIndices) 
throws InternalDataStoreException
     {
         int columnCount = columnIndices.size();
         if (columnCount != 0) sql.append(", ");
+        if (function != null) {
+            sql.appendIdentifier(database.catalogOfSpatialTables, 
database.schemaOfSpatialTables, function, false).append('(');
+        }
         sql.appendIdentifier(column);
+        if (function != null) {
+            sql.append(')');
+        }
         if (columnIndices.put(column, ++columnCount) == null) return 
columnCount;
         throw new 
InternalDataStoreException(Resources.format(Resources.Keys.DuplicatedColumn_1, 
column));
     }
@@ -301,7 +313,7 @@ final class FeatureAdapter {
         final int[] indices = new int[columns.size()];
         for (final String column : columns) {
             final Integer pos = columnIndices.get(column);
-            indices[i++] = (pos != null) ? pos : appendColumn(sql, column, 
columnIndices);
+            indices[i++] = (pos != null) ? pos : appendColumn(sql, null, null, 
column, columnIndices);
         }
         return indices;
     }
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/GeometryEncoding.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/GeometryEncoding.java
index 544d0596ed..73eb41fc0a 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/GeometryEncoding.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/GeometryEncoding.java
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.storage.sql.feature;
 
+import java.util.EnumMap;
+
 
 /**
  * The encoding to use for reading or writing geometries from a {@code 
ResultSet}, in preference order.
@@ -29,11 +31,98 @@ public enum GeometryEncoding {
     /**
      * Use Well-Known Binary (<abbr>WKB</abbr>) format.
      * Includes the Geopackage geometry encoding extension, which is 
identified by the "GP" prefix.
+     *
+     * <p>If the extended <abbr>WKB</abbr> format is supported, then {@code 
SQLStore} will use that function
+     * despite the fact that it is non-standard, in order to get the 
coordinate reference system associated
+     * with the geometry. Otherwise, the <abbr>SQLMM</abbr> standard function 
for fetching this value from
+     * a database is {@code "ST_AsBinary"}. However, some databases expect 
{@code "ST_AsWKB"} instead.</p>
      */
-    WKB,
+    WKB(new String[] {"ST_AsEWKB", "ST_AsBinary", "ST_AsWKB"}),
 
     /**
      * Use Well-Known Text (<abbr>WKT</abbr>) format.
+     *
+     * <p>The <abbr>SQLMM</abbr> standard function for fetching this value 
from a database is {@code "ST_AsText"}.
+     * However, some databases expect {@code "ST_AsWKT"} instead.</p>
+     */
+    WKT(new String[] {"ST_AsText", "ST_AsWKT"});
+
+    /**
+     * The functions to use, in preference order, for getting the value from 
the database.
+     */
+    private final String[] readers;
+
+    /**
+     * Creates a new enumeration value.
+     *
+     * @param readers  the functions to use, in preference order, for getting 
the value from the database.
+     */
+    private GeometryEncoding(final String[] readers) {
+        this.readers = readers;
+    }
+
+    /**
+     * All enumeration values, fetching once for avoiding multiple array 
creations.
+     */
+    private static final GeometryEncoding[] VALUES = values();
+
+    /**
+     * Creates an initially empty array to use as argument in the calls to 
{@code checkSupport(…)} method.
+     * Should be considered as an opaque storage mechanism used by this class 
only.
+     *
+     * @see #checkSupport(String[][], String)
+     */
+    static String[][] initial() {
+        return new String[VALUES.length][];
+    }
+
+    /**
+     * Invoked in a loop over for identifying which functions are supported 
for fetching or storing geometries.
+     *
+     * @param accessors  the array created by {@link #initial()}.
+     * @param function   a function of the database.
+     *
+     * @todo Add a loop over {@code writers} after we implemented write 
support.
+     */
+    static void checkSupport(final String[][] accessors, final String 
function) {
+        for (int j=0; j < VALUES.length; j++) {
+            final GeometryEncoding encoding = VALUES[j];
+            final String[] readers = encoding.readers;
+            for (int i=0; i < readers.length; i++) {
+                if (readers[i].equalsIgnoreCase(function)) {
+                    String[] functions = accessors[j];
+                    if (functions == null) {
+                        functions = new String[readers.length];
+                        accessors[j] = functions;
+                    }
+                    functions[i] = function;    // Keep the case used by the 
database.
+                }
+            }
+        }
+    }
+
+    /**
+     * Puts in the given map the preferred functions for fetching or storing 
geometries.
+     * If many functions are supported, the standard one is preferred.
+     *
+     * @param  accessors  the array created by {@link #initial()}.
+     * @param  target     where to store the preferred functions for fetching 
or storing geometries.
+     *
+     * @todo Add an argument for specifying whether read or write operation is 
desired.
      */
-    WKT
+    static void store(final String[][] accessors, final 
EnumMap<GeometryEncoding, String> target) {
+next:   for (int j=0; j < accessors.length; j++) {
+            final GeometryEncoding encoding = VALUES[j];
+            final String[] functions = accessors[j];
+            if (functions != null) {
+                for (String function : functions) {
+                    if (function != null) {
+                        target.put(encoding, function);     // We want the 
function at the lowest index.
+                        continue next;
+                    }
+                }
+            }
+            target.remove(encoding);
+        }
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/InfoStatements.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/InfoStatements.java
index 34d4a25d5c..294cd19b51 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/InfoStatements.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/InfoStatements.java
@@ -320,7 +320,7 @@ public class InfoStatements implements Localized, 
AutoCloseable {
                             type = GeometryType.GEOMETRY;
                         }
                     }
-                    target.makeSpatial(this, type, crs);
+                    target.makeSpatial(database, type, crs);
                 }
             }
         }
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/QueryAnalyzer.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/QueryAnalyzer.java
index aa2f7b8ce3..b474ece77a 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/QueryAnalyzer.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/QueryAnalyzer.java
@@ -155,9 +155,12 @@ final class QueryAnalyzer extends FeatureAnalyzer {
     Column[] createAttributes() throws Exception {
         /*
          * Identify geometry columns. Must be done before the calls to 
`Analyzer.setValueGetterOf(column)`.
+         * If the database does not have a "geometry columns" table, parse 
field type names as a fallback.
          */
+        boolean fallback = true;
         final InfoStatements spatialInformation = analyzer.spatialInformation;
         if (spatialInformation != null) {
+            fallback = columnsPerTable.isEmpty();
             for (final Map.Entry<TableReference, Map<String,Column>> entry : 
columnsPerTable.entrySet()) {
                 spatialInformation.completeIntrospection(analyzer, 
entry.getKey(), entry.getValue());
             }
@@ -167,6 +170,9 @@ final class QueryAnalyzer extends FeatureAnalyzer {
          */
         final var attributes = new ArrayList<Column>();
         for (final Column column : columns) {
+            if (fallback) {
+                column.tryMakeSpatial(analyzer.database);
+            }
             if (createAttribute(column)) {
                 attributes.add(column);
             }
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SelectionClauseWriter.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SelectionClauseWriter.java
index 5468a84c63..2f4cb10fd3 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SelectionClauseWriter.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SelectionClauseWriter.java
@@ -150,6 +150,7 @@ public class SelectionClauseWriter extends Visitor<Feature, 
SelectionClause> {
      */
     final SelectionClauseWriter removeUnsupportedFunctions(final Database<?> 
database) {
         final var unsupported = new HashMap<String, SpatialOperatorName>();
+        final var accessors = GeometryEncoding.initial();
         try (Connection c = database.source.getConnection()) {
             final DatabaseMetaData metadata = c.getMetaData();
             /*
@@ -178,7 +179,9 @@ public class SelectionClauseWriter extends Visitor<Feature, 
SelectionClause> {
                                                      prefix + '%'))
             {
                 while (r.next()) {
-                    unsupported.remove(r.getString("FUNCTION_NAME"));
+                    final String function = r.getString("FUNCTION_NAME");
+                    GeometryEncoding.checkSupport(accessors, function);
+                    unsupported.remove(function);
                 }
             }
         } catch (SQLException e) {
@@ -188,6 +191,7 @@ public class SelectionClauseWriter extends Visitor<Feature, 
SelectionClause> {
              */
             database.listeners.warning(e);
         }
+        database.setGeometryEncodingFunctions(accessors);
         /*
          * Remaining functions are unsupported functions.
          */
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/TableAnalyzer.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/TableAnalyzer.java
index 728e8e1d9c..291a1797b5 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/TableAnalyzer.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/TableAnalyzer.java
@@ -187,6 +187,10 @@ final class TableAnalyzer extends FeatureAnalyzer {
          */
         final var attributes = new ArrayList<Column>();
         for (final Column column : columns.values()) {
+            if (spatialInformation == null) {
+                // Fallback for databases without "geometry columns" table.
+                column.tryMakeSpatial(analyzer.database);
+            }
             if (createAttribute(column)) {
                 attributes.add(column);
             }
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/ValueGetter.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/ValueGetter.java
index dd1253b117..24e250c21f 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/ValueGetter.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/ValueGetter.java
@@ -472,7 +472,7 @@ public class ValueGetter<T> {
     }
 
     /**
-     * Converts the given SQL array to a Java array and free the SQL array.
+     * Converts the given SQL array to a Java array and frees the SQL array.
      * The returned array may be a primitive array or an array of objects.
      *
      * @param  stmts  information about the statement being executed, or 
{@code null} if none.
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/postgis/Postgres.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/postgis/Postgres.java
index a68494cd8f..519257998f 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/postgis/Postgres.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/postgis/Postgres.java
@@ -158,10 +158,12 @@ public final class Postgres<G> extends Database<G> {
     /**
      * Returns an identifier of the way binary data are encoded by the JDBC 
driver.
      * Data stored as PostgreSQL {@code BYTEA} type are encoded in hexadecimal.
+     * Geometry type are handled as binary because of the insertion of the SQL
+     * function {@code ST_AsBinary(column)}.
      */
     @Override
     protected BinaryEncoding getBinaryEncoding(final Column columnDefinition) {
-        if (columnDefinition.type == Types.BLOB) {
+        if (columnDefinition.type == Types.BLOB || 
columnDefinition.getGeometryType().isPresent()) {
             return super.getBinaryEncoding(columnDefinition);
         } else {
             return BinaryEncoding.HEXADECIMAL;

Reply via email to