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); } }
