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

commit 531f0165a64d21c1d193d3dfa9c1ec076e01a3ed
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sat Jun 28 13:37:01 2025 +0200

    Write catalog name in a way more compliant with what the database driver 
expects.
    Omit the catalog name and/or schema name when they are the current 
catalog/schema.
---
 .../apache/sis/metadata/sql/MetadataSource.java    |  6 +-
 .../org/apache/sis/metadata/sql/privy/Dialect.java | 20 +-----
 .../apache/sis/metadata/sql/privy/Reflection.java  |  2 -
 .../apache/sis/metadata/sql/privy/SQLBuilder.java  | 59 +++++++++--------
 .../sis/metadata/sql/privy/SQLUtilities.java       |  3 +-
 .../apache/sis/metadata/sql/privy/Supports.java    | 12 +---
 .../org/apache/sis/metadata/sql/privy/Syntax.java  | 76 +++++++++++++++++-----
 .../apache/sis/storage/sql/feature/Analyzer.java   |  5 +-
 .../apache/sis/storage/sql/feature/Database.java   |  6 +-
 .../sis/storage/sql/feature/FeatureAdapter.java    |  4 +-
 .../sis/storage/sql/feature/FeatureIterator.java   |  4 +-
 .../sis/storage/sql/feature/FeatureStream.java     | 34 +++++-----
 .../sis/storage/sql/feature/InfoStatements.java    | 17 +++--
 .../sis/storage/sql/postgis/ExtentEstimator.java   |  6 +-
 .../apache/sis/storage/sql/postgis/Postgres.java   |  2 +-
 15 files changed, 147 insertions(+), 109 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataSource.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataSource.java
index 1a17908534..804509ff65 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataSource.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/MetadataSource.java
@@ -750,8 +750,10 @@ public class MetadataSource implements AutoCloseable {
                     } else {
                         final Class<?> type = value.getClass();
                         if (standard.isMetadata(type)) {
-                            dependency = 
search(getTableName(standard.getInterface(type)),
-                                    null, asValueMap(value), stmt, new 
SQLBuilder(helper));
+                            final var builder = new SQLBuilder(helper);
+                            builder.setCatalogAndSchema(stmt.getConnection());
+                            final String other = 
getTableName(standard.getInterface(type));
+                            dependency = search(other, null, 
asValueMap(value), stmt, builder);
                             if (dependency == null) {
                                 return null;                    // Dependency 
not found.
                             }
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Dialect.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Dialect.java
index ddec3b61ab..816741e419 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Dialect.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Dialect.java
@@ -18,7 +18,6 @@ package org.apache.sis.metadata.sql.privy;
 
 import java.sql.SQLException;
 import java.sql.DatabaseMetaData;
-import org.apache.sis.util.Workaround;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.privy.Constants;
 
@@ -40,7 +39,6 @@ public enum Dialect {
              | Supports.JAVA_TIME
              | Supports.READ_ONLY_UPDATE
              | Supports.CONCURRENCY
-             | Supports.CATALOG
              | Supports.SRID),
 
     /**
@@ -52,8 +50,7 @@ public enum Dialect {
      */
     DERBY("derby", Supports.ALTER_TABLE_WITH_ADD_CONSTRAINT
                  | Supports.READ_ONLY_UPDATE
-                 | Supports.CONCURRENCY
-                 | Supports.CATALOG),
+                 | Supports.CONCURRENCY),
 
     /**
      * The database uses HSQL syntax. This is ANSI, but does not allow {@code 
INSERT} statements inserting many lines.
@@ -62,8 +59,7 @@ public enum Dialect {
     HSQL("hsqldb", Supports.ALTER_TABLE_WITH_ADD_CONSTRAINT
                  | Supports.JAVA_TIME
                  | Supports.READ_ONLY_UPDATE
-                 | Supports.CONCURRENCY
-                 | Supports.CATALOG),
+                 | Supports.CONCURRENCY),
 
     /**
      * The database uses PostgreSQL syntax. This is ANSI, but provided an a 
separated
@@ -74,7 +70,6 @@ public enum Dialect {
                            | Supports.JAVA_TIME
                            | Supports.READ_ONLY_UPDATE
                            | Supports.CONCURRENCY
-                           | Supports.CATALOG
                            | Supports.SRID),
 
     /**
@@ -84,7 +79,6 @@ public enum Dialect {
                    | Supports.JAVA_TIME
                    | Supports.READ_ONLY_UPDATE
                    | Supports.CONCURRENCY
-                   | Supports.CATALOG
                    | Supports.SRID),
 
     /**
@@ -193,16 +187,6 @@ public enum Dialect {
         return (flags & Supports.CONCURRENCY) != 0;
     }
 
-    /**
-     * Whether the JDBC driver supports catalog or correctly reports that 
there is no catalog.
-     * This flag should be {@code false} when the JDBC driver returns a 
non-null catalog name
-     * (for example, the database name) but doesn't accept the use of that 
catalog in SQL.
-     */
-    @Workaround(library = "DuckDB", version = "1.2.2.0")
-    public final boolean supportsCatalog() {
-        return (flags & Supports.CATALOG) != 0;
-    }
-
     /**
      * Whether the spatial extension supports <abbr>SRID</abbr> in {@code 
ST_*} functions.
      */
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Reflection.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Reflection.java
index b2a87ca14a..1069b2682a 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Reflection.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Reflection.java
@@ -41,8 +41,6 @@ public final class Reflection {
      * The {@value} key for getting a catalog name. This column appears in all 
reflection
      * operations (listing schemas, tables, columns, constraints, <i>etc.</i>) 
used by SIS.
      * The value in that column may be null.
-     *
-     * @see Dialect#supportsCatalog()
      */
     public static final String TABLE_CAT = "TABLE_CAT";
 
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/SQLBuilder.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/SQLBuilder.java
index dba6153af5..394fdb6db1 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/SQLBuilder.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/SQLBuilder.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.metadata.sql.privy;
 
+import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
 import java.time.LocalDate;
@@ -24,6 +25,7 @@ import java.time.ZoneOffset;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalQueries;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.privy.Strings;
 
 
 /**
@@ -163,7 +165,7 @@ public class SQLBuilder extends Syntax {
      * @return this builder, for method call chaining.
      */
     public final SQLBuilder appendIdentifier(final String name) {
-        buffer.append(quote).append(name).append(quote);
+        buffer.append(identifierQuote).append(name).append(identifierQuote);
         return this;
     }
 
@@ -191,34 +193,45 @@ public class SQLBuilder extends Syntax {
      * Unquoted names are useful when the name is for built-in functions,
      * which often use the lower/upper case convention of the database.
      *
+     * <h4>Simplification</h4>
+     * If the given catalog is equal to the {@linkplain 
Connection#getCatalog() catalog which was current} when
+     * {@link #setCatalogAndSchema(Connection)} has been invoked, then the 
catalog name is omitted for simplicty.
+     * Likewise, if the given schema is equal to the {@linkplain 
Connection#getSchema() current schema},
+     * then the schema name will also be omitted.
+     *
      * @param  catalog    the catalog, or {@code null} or empty if none.
      * @param  schema     the schema, or {@code null} or empty if none.
      * @param  name       the name part of the identifier to append.
      * @param  quoteName  whether to quote the name part.
      * @return this builder, for method call chaining.
      */
-    public final SQLBuilder appendIdentifier(final String catalog, final 
String schema, final String name, final boolean quoteName) {
-        if (catalog != null && !catalog.isEmpty()) {
-            appendIdentifier(catalog);
-            buffer.append('.');
-            if (schema == null || schema.isEmpty()) {
-                buffer.append(quote).append(quote).append('.');
+    public final SQLBuilder appendIdentifier(final String catalog, String 
schema, final String name, final boolean quoteName) {
+        boolean showSchema  = !(Strings.isNullOrEmpty(schema)  || schema 
.equals(currentSchema));
+        boolean showCatalog = !(Strings.isNullOrEmpty(catalog) || 
catalog.equals(currentCatalog) || Strings.isNullOrEmpty(catalogSeparator));
+        if (showCatalog && isCatalogAtStart) {
+            appendIdentifier(catalog).append(catalogSeparator);
+            showSchema = true;
+            if (schema == null) {
+                schema = "";
             }
         }
-        if (schema != null && !schema.isEmpty()) {
+        if (showSchema) {
             if (quoteSchema) {
                 appendIdentifier(schema);
             } else {
-                buffer.append(schema);
+                append(schema);
             }
-            buffer.append('.');
+            append('.');
         }
         if (quoteName) {
-            return appendIdentifier(name);
+            appendIdentifier(name);
         } else {
-            buffer.append(name);
-            return this;
+            append(name);
+        }
+        if (showCatalog && !isCatalogAtStart) {
+            append(catalogSeparator).appendIdentifier(catalog);
         }
+        return this;
     }
 
     /**
@@ -229,12 +242,7 @@ public class SQLBuilder extends Syntax {
      * @return this builder, for method call chaining.
      */
     public final SQLBuilder appendEqualsValue(final Object value) {
-        if (value == null) {
-            buffer.append(" IS NULL");
-            return this;
-        }
-        buffer.append('=');
-        return appendValue(value);
+        return (value == null) ? append(" IS NULL") : 
append('=').appendValue(value);
     }
 
     /**
@@ -245,12 +253,7 @@ public class SQLBuilder extends Syntax {
      * @return this builder, for method call chaining.
      */
     public final SQLBuilder appendValue(final String value) {
-        if (value == null) {
-            buffer.append("NULL");
-        } else {
-            buffer.append('\'').append(value.replace("'", "''")).append('\'');
-        }
-        return this;
+        return (value == null) ? append("NULL") : 
append('\'').append(value.replace("'", "''")).append('\'');
     }
 
     /**
@@ -327,11 +330,11 @@ public class SQLBuilder extends Syntax {
         final int start = buffer.length();
         buffer.append(value);
         if (canEscapeWildcards()) {
-            final char escapeChar = escape.charAt(0);
+            final char escapeChar = wildcardEscape.charAt(0);
             for (int i = buffer.length(); --i >= start;) {
                 final char c = buffer.charAt(i);
-                if (c == '_' || c == '%' || (c == escapeChar && 
value.startsWith(escape, i))) {
-                    buffer.insert(i, escape);
+                if (c == '_' || c == '%' || (c == escapeChar && 
value.startsWith(wildcardEscape, i))) {
+                    buffer.insert(i, wildcardEscape);
                 }
             }
         }
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/SQLUtilities.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/SQLUtilities.java
index a547856773..c4b9881d55 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/SQLUtilities.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/SQLUtilities.java
@@ -23,6 +23,7 @@ import org.apache.sis.util.Static;
 import org.apache.sis.util.Characters;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Workaround;
+import org.apache.sis.util.privy.Strings;
 import org.apache.sis.util.resources.Errors;
 
 
@@ -116,7 +117,7 @@ public final class SQLUtilities extends Static {
      * @return the given text with wildcard characters escaped.
      */
     public static String escape(final String text, final String escape) {
-        if (text != null && escape != null && !escape.isEmpty()) {
+        if (text != null && !Strings.isNullOrEmpty(escape)) {
             final char escapeChar = escape.charAt(0);
             StringBuilder buffer = null;
             for (int i = text.length(); --i >= 0;) {
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Supports.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Supports.java
index 0820e1ea8f..d03cbe4f97 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Supports.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Supports.java
@@ -16,8 +16,6 @@
  */
 package org.apache.sis.metadata.sql.privy;
 
-import org.apache.sis.util.Workaround;
-
 
 /**
  * Enumeration of features that may be supported by a database.
@@ -68,18 +66,10 @@ final class Supports {
      */
     static final int CONCURRENCY = 32;
 
-    /**
-     * Whether the JDBC driver supports catalog or correctly reports that 
there is no catalog.
-     * This flag should be {@code false} when the JDBC driver returns a 
non-null catalog name
-     * (for example, the database name) but doesn't accept the use of that 
catalog in SQL.
-     */
-    @Workaround(library = "DuckDB", version = "1.2.2.0")
-    static final int CATALOG = 64;
-
     /**
      * Whether the spatial extension supports <abbr>SRID</abbr> in {@code 
ST_*} functions.
      */
-    static final int SRID = 128;
+    static final int SRID = 64;
 
     /**
      * Do not allow instantiation of this class.
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Syntax.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Syntax.java
index 335aa2f276..ae9281ee90 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Syntax.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/sql/privy/Syntax.java
@@ -16,12 +16,14 @@
  */
 package org.apache.sis.metadata.sql.privy;
 
+import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
+import org.apache.sis.util.privy.Strings;
 
 
 /**
- * Information about the syntax to use for building SQL statements.
+ * Information about the syntax to use for building <abbr>SQL</abbr> 
statements.
  * This object extract from {@link DatabaseMetaData} the information needed by 
{@link SQLBuilder}.
  * It can be cached if many {@link SQLBuilder} instances are going to be 
created.
  *
@@ -33,11 +35,22 @@ public class Syntax {
      */
     public final Dialect dialect;
 
+    /**
+     * Whether a catalog appears at the start of a fully qualified table name.
+     * If not, the catalog appears at the end.
+     */
+    final boolean isCatalogAtStart;
+
+    /**
+     * The character that the database uses as the separator between a catalog 
and table name.
+     */
+    final String catalogSeparator;
+
     /**
      * The characters used for quoting identifiers, or an empty string if none.
      * This is the value returned by {@link 
DatabaseMetaData#getIdentifierQuoteString()}.
      */
-    final String quote;
+    final String identifierQuote;
 
     /**
      * Whether the schema name should be written between quotes. If {@code 
false},
@@ -61,7 +74,17 @@ public class Syntax {
      * @see #escapeWildcards(String)
      * @see SQLBuilder#appendWildcardEscaped(String)
      */
-    final String escape;
+    final String wildcardEscape;
+
+    /**
+     * The default catalog of the connection, or {@code null} if none.
+     */
+    String currentCatalog;
+
+    /**
+     * The default schema of the connection, or {@code null} if none.
+     */
+    String currentSchema;
 
     /**
      * Creates a new {@code Syntax} initialized from the given database 
metadata.
@@ -72,13 +95,18 @@ public class Syntax {
      */
     public Syntax(final DatabaseMetaData metadata, final boolean quoteSchema) 
throws SQLException {
         if (metadata != null) {
-            dialect = Dialect.guess(metadata);
-            quote   = metadata.getIdentifierQuoteString();
-            escape  = metadata.getSearchStringEscape();
+            dialect          = Dialect.guess(metadata);
+            isCatalogAtStart = metadata.isCatalogAtStart();
+            catalogSeparator = metadata.getCatalogSeparator();
+            identifierQuote  = metadata.getIdentifierQuoteString();
+            wildcardEscape   = metadata.getSearchStringEscape();
+            setCatalogAndSchema(metadata.getConnection());
         } else {
-            dialect = Dialect.ANSI;
-            quote   = "\"";
-            escape  = null;
+            dialect          = Dialect.ANSI;
+            isCatalogAtStart = true;
+            catalogSeparator = ".";
+            identifierQuote  = "\"";
+            wildcardEscape   = null;
         }
         this.quoteSchema = quoteSchema;
     }
@@ -89,10 +117,28 @@ public class Syntax {
      * @param  other  the template from which to copy metadata.
      */
     Syntax(final Syntax other) {
-        dialect     = other.dialect;
-        escape      = other.escape;
-        quote       = other.quote;
-        quoteSchema = other.quoteSchema;
+        dialect          = other.dialect;
+        isCatalogAtStart = other.isCatalogAtStart;
+        catalogSeparator = other.catalogSeparator;
+        identifierQuote  = other.identifierQuote;
+        wildcardEscape   = other.wildcardEscape;
+        currentCatalog   = other.currentCatalog;
+        currentSchema    = other.currentSchema;
+        quoteSchema      = other.quoteSchema;
+    }
+
+    /**
+     * Sets the current catalog and schema.
+     * When {@linkplain SQLBuilder#appendIdentifier(String, String, String, 
boolean) formatting an identifier},
+     * then given catalog and/or schema may be omitted if equal to the current 
catalog and/or schema, in order
+     * to make the <abbr>SQL</abbr> statement simpler.
+     *
+     * @param  current  the connection which will execute the <abbr>SQL</abbr> 
statement.
+     * @throws SQLException if an error occurred while fetching information 
from the connection.
+     */
+    public final void setCatalogAndSchema(final Connection current) throws 
SQLException {
+        currentCatalog = current.getCatalog();
+        currentSchema  = current.getSchema();
     }
 
     /**
@@ -120,7 +166,7 @@ public class Syntax {
      * @return the given text with wildcard characters escaped.
      */
     public final String escapeWildcards(final String text) {
-        return SQLUtilities.escape(text, escape);
+        return SQLUtilities.escape(text, wildcardEscape);
     }
 
     /**
@@ -134,6 +180,6 @@ public class Syntax {
      * @return whether the database can escape wildcard characters.
      */
     public final boolean canEscapeWildcards() {
-        return (escape != null) && !escape.isEmpty();
+        return !Strings.isNullOrEmpty(wildcardEscape);
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Analyzer.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Analyzer.java
index e9d3e110bc..081aff5ab6 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Analyzer.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Analyzer.java
@@ -237,10 +237,7 @@ public final class Analyzer {
                     if (ignoredTables.containsKey(table)) {
                         continue;
                     }
-                    String catalog = null;
-                    if (database.dialect.supportsCatalog()) {
-                        catalog = getUniqueString(reflect, 
Reflection.TABLE_CAT);
-                    }
+                    String catalog = getUniqueString(reflect, 
Reflection.TABLE_CAT);
                     declared.add(new TableReference(catalog,
                             getUniqueString(reflect, Reflection.TABLE_SCHEM), 
table,
                             getUniqueString(reflect, Reflection.REMARKS)));
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 a23de1476c..e31841ef3b 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
@@ -319,7 +319,7 @@ public class Database<G> extends Syntax  {
         this.cacheOfCRS    = new Cache<>(7, 2, false);
         this.cacheOfSRID   = new WeakHashMap<>();
         this.tablesByNames = new FeatureNaming<>();
-        supportsCatalogs   = dialect.supportsCatalog() && 
metadata.supportsCatalogsInDataManipulation();
+        supportsCatalogs   = metadata.supportsCatalogsInDataManipulation();
         supportsSchemas    = metadata.supportsSchemasInDataManipulation();
         supportsJavaTime   = dialect.supportsJavaTime();
         crsEncodings       = EnumSet.noneOf(CRSEncoding.class);
@@ -410,9 +410,7 @@ public class Database<G> extends Syntax  {
             if (found) {
                 spatialSchema = convention;
                 if (consistent) {
-                    if (dialect.supportsCatalog()) {
-                        catalogOfSpatialTables = catalog;
-                    }
+                    catalogOfSpatialTables = catalog;
                     schemaOfSpatialTables = schema;
                 }
                 break;
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 5aedba02ed..de957bb0ae 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
@@ -168,7 +168,9 @@ final class FeatureAdapter {
          * Order matter, because `FeatureIterator` iterator will map the 
columns
          * to the attributes listed in the `attributes` array in that order.
          */
-        final var sql = new 
SQLBuilder(table.database).append(SQLBuilder.SELECT);
+        final var sql = new SQLBuilder(table.database);
+        sql.setCatalogAndSchema(metadata.getConnection());
+        sql.append(SQLBuilder.SELECT);
         for (final Column column : attributes) {
             String function = null;
             if (column.getGeometryType().isPresent()) {
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureIterator.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureIterator.java
index 4636952051..12904c2eed 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureIterator.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureIterator.java
@@ -142,7 +142,9 @@ final class FeatureIterator implements 
Spliterator<Feature>, AutoCloseable {
         }
         final String filter = (selection != null) ? 
selection.query(connection, spatialInformation) : null;
         if (distinct || filter != null || sort != null || (offset | count) != 
0) {
-            final var builder = new SQLBuilder(table.database).append(sql);
+            final var builder = new SQLBuilder(table.database);
+            builder.setCatalogAndSchema(connection);
+            builder.append(sql);
             if (distinct) {
                 builder.insertDistinctAfterSelect();
             }
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureStream.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureStream.java
index 2386a8fa35..6d7f3aa463 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureStream.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/FeatureStream.java
@@ -331,25 +331,27 @@ final class FeatureStream extends DeferredStream<Feature> 
{
         if (hasPredicates || count != 0) {
             return super.count();
         }
-        /*
-         * Build the full SQL statement here, without using 
`FeatureAdapter.sql`,
-         * because we do not need to follow foreigner keys.
-         */
-        final var sql = new 
SQLBuilder(table.database).append(SQLBuilder.SELECT).append("COUNT(");
-        if (distinct) {
-            String separator = "DISTINCT ";
-            for (final Column attribute : table.attributes) {
-                sql.append(separator).appendIdentifier(attribute.label);
-                separator = ", ";
-            }
-        } else {
-            // If we want a count and no distinct clause is specified, a 
single column is sufficient.
-            sql.appendIdentifier(table.attributes[0].label);
-        }
-        table.appendFromClause(sql.append(')'));
         lock(table.database.transactionLocks);
         try (Connection connection = getConnection()) {
             makeReadOnly(connection);
+            /*
+             * Build the full SQL statement here, without using 
`FeatureAdapter.sql`,
+             * because we do not need to follow foreigner keys.
+             */
+            final var sql = new SQLBuilder(table.database);
+            sql.setCatalogAndSchema(connection);
+            sql.append(SQLBuilder.SELECT).append("COUNT(");
+            if (distinct) {
+                String separator = "DISTINCT ";
+                for (final Column attribute : table.attributes) {
+                    sql.append(separator).appendIdentifier(attribute.label);
+                    separator = ", ";
+                }
+            } else {
+                // If we want a count and no distinct clause is specified, a 
single column is sufficient.
+                sql.appendIdentifier(table.attributes[0].label);
+            }
+            table.appendFromClause(sql.append(')'));
             if (selection != null) {
                 final String filter = selection.query(connection, null);
                 if (filter != null) {
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 9b7981d788..a8aae84641 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
@@ -200,6 +200,15 @@ public class InfoStatements implements Localized, 
AutoCloseable {
         return database.listeners.getLocale();
     }
 
+    /**
+     * Returns a new builder of <abbr>SQL</abbr> statement.
+     */
+    private SQLBuilder builder() throws SQLException {
+        final var builder = new SQLBuilder(database);
+        builder.setCatalogAndSchema(connection);
+        return builder;
+    }
+
     /**
      * Appends a {@code " FROM <table> WHERE "} text to the given builder.
      * The table name will be prefixed by catalog and schema name if 
applicable.
@@ -250,7 +259,7 @@ public class InfoStatements implements Localized, 
AutoCloseable {
             return null;
         }
         final SpatialSchema schema = database.getSpatialSchema().orElseThrow();
-        final var sql = new SQLBuilder(database).append(SQLBuilder.SELECT);
+        final var sql = builder().append(SQLBuilder.SELECT);
         if (geomColNameColumn == null) {
             geomColNameColumn = schema.geomColNameColumn;
         }
@@ -397,7 +406,7 @@ public class InfoStatements implements Localized, 
AutoCloseable {
                 return null;
             }
             final SpatialSchema schema = 
database.getSpatialSchema().orElseThrow();
-            final var sql = new SQLBuilder(database)
+            final var sql = builder()
                     .append(SQLBuilder.SELECT).append("DISTINCT ")
                     .appendIdentifier(schema.crsIdentifierColumn)
                     .append(" FROM ").appendIdentifier(schema.geometryColumns)
@@ -465,7 +474,7 @@ public class InfoStatements implements Localized, 
AutoCloseable {
             search = schema.crsIdentifierColumn;
             get    = schema.crsAuthorityCodeColumn;
         }
-        final var sql = new SQLBuilder(database).append(SQLBuilder.SELECT)
+        final var sql = builder().append(SQLBuilder.SELECT)
                 .append(schema.crsAuthorityNameColumn).append(", 
").append(get);
 
         for (CRSEncoding encoding : database.crsEncodings) {
@@ -884,7 +893,7 @@ public class InfoStatements implements Localized, 
AutoCloseable {
      */
     private int addCRS(final SRID search, final Set<Integer> sridFounInUse) 
throws Exception {
         final SpatialSchema schema = database.getSpatialSchema().orElseThrow();
-        final var sql = new SQLBuilder(database).append(SQLBuilder.INSERT);
+        final var sql = builder().append(SQLBuilder.INSERT);
         database.formatTableName(sql, schema.crsTable);
         sql.append(" (").append(schema.crsIdentifierColumn)
            .append(", ").append(schema.crsAuthorityNameColumn)
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/postgis/ExtentEstimator.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/postgis/ExtentEstimator.java
index d11dd644fb..8435ab0a00 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/postgis/ExtentEstimator.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/postgis/ExtentEstimator.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.storage.sql.postgis;
 
+import java.sql.Connection;
 import java.sql.Statement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -79,11 +80,14 @@ final class ExtentEstimator {
     /**
      * Creates a new extent estimator for the specified table.
      */
-   ExtentEstimator(final Database<?> database, final TableReference table, 
final Column[] columns) {
+   ExtentEstimator(final Database<?> database, final TableReference table, 
final Column[] columns, final Connection c)
+           throws SQLException
+   {
         this.database = database;
         this.table    = table;
         this.columns  = columns;
         this.builder  = new SQLBuilder(database);
+        builder.setCatalogAndSchema(c);
     }
 
     /**
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 739bf969b4..d4917c1229 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
@@ -230,8 +230,8 @@ public final class Postgres<G> extends Database<G> {
     protected Envelope getEstimatedExtent(final TableReference table, final 
Column[] columns, final boolean recall)
             throws SQLException
     {
-        final ExtentEstimator ex = new ExtentEstimator(this, table, columns);
         try (Connection c = source.getConnection(); Statement statement = 
c.createStatement()) {
+            final ExtentEstimator ex = new ExtentEstimator(this, table, 
columns, c);
             return ex.estimate(statement, recall);
         }
     }

Reply via email to