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 5e694bfb26 Fix a DataStoreException about duplicated identifier when a 
table contains 2 foreigner keys referencing the same table. 
https://issues.apache.org/jira/browse/SIS-606
5e694bfb26 is described below

commit 5e694bfb2606f921a5344512b0d909724dac8bdc
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Tue Oct 22 20:30:20 2024 +0200

    Fix a DataStoreException about duplicated identifier when a table contains 
2 foreigner keys referencing the same table.
    https://issues.apache.org/jira/browse/SIS-606
---
 .../org/apache/sis/storage/sql/feature/Analyzer.java    |  7 +++----
 .../apache/sis/storage/sql/feature/FeatureAdapter.java  | 11 ++++++-----
 .../org/apache/sis/storage/sql/feature/PrimaryKey.java  | 12 ++++++++++++
 .../apache/sis/storage/sql/feature/QueryAnalyzer.java   |  6 +++---
 .../org/apache/sis/storage/sql/feature/Relation.java    | 17 ++++++++++++-----
 .../main/org/apache/sis/storage/sql/feature/Table.java  |  4 +---
 .../apache/sis/storage/sql/feature/TableAnalyzer.java   | 10 ++++------
 7 files changed, 41 insertions(+), 26 deletions(-)

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 645ea0bd47..d83976afba 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
@@ -227,8 +227,7 @@ public final class Analyzer {
          * specified name. During this iteration, we may discover new tables 
to analyze because of dependencies
          * (foreigner keys).
          */
-        final List<Table> tableList;
-        tableList = new ArrayList<>(tableNames.length);
+        final var tableList = new ArrayList<Table>(tableNames.length);
         for (final TableReference reference : declared) {
             // Adds only the table explicitly required by the user.
             tableList.add(table(reference, reference.getName(this), null));
@@ -246,8 +245,8 @@ public final class Analyzer {
     /**
      * Reads a string from the given result set and return a unique instance 
of that string.
      * This method should be invoked only for {@code String} instances that 
are going to be
-     * stored in {@link Table} or {@link Relation} structures; there is no 
point to invoke
-     * this method for example before to parse the string as a boolean.
+     * stored in {@link Table} or {@link Relation} structures. There is no 
point to invoke
+     * this method for example before to parse the string as a Boolean.
      *
      * @param  reflect  the result set from which to read a string.
      * @param  column   the column to read.
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 53c794b92c..5ce00aa6f8 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
@@ -150,6 +150,7 @@ final class FeatureAdapter {
      * @param following  the relations that we are following. Used for 
avoiding never ending loop.
      * @param noFollow   relation to not follow, or {@code null} if none.
      */
+    @SuppressWarnings("LocalVariableHidesMemberVariable")
     private FeatureAdapter(final Table table, final DatabaseMetaData metadata,
                            final List<Relation> following, final Relation 
noFollow)
              throws SQLException, InternalDataStoreException
@@ -161,13 +162,13 @@ final class FeatureAdapter {
         } else {
             keyComponentClass = null;
         }
-        final Map<String,Integer> columnIndices = new HashMap<>();
+        final var columnIndices = new HashMap<String,Integer>();
         /*
          * Create a SELECT clause with all columns that are ordinary 
attributes.
          * Order matter, because `FeatureIterator` iterator will map the 
columns
          * to the attributes listed in the `attributes` array in that order.
          */
-        final SQLBuilder sql = new 
SQLBuilder(table.database).append(SQLBuilder.SELECT);
+        final var sql = new 
SQLBuilder(table.database).append(SQLBuilder.SELECT);
         for (final Column column : attributes) {
             appendColumn(sql, column.label, columnIndices);
         }
@@ -185,9 +186,9 @@ final class FeatureAdapter {
             deferredAssociation = null;
         } else {
             String deferredAssociation = null;
-            final FeatureAdapter[] dependencies        = new 
FeatureAdapter[count];
-            final String[]         associationNames    = new String[count];
-            final int[][]          foreignerKeyIndices = new int[count][];
+            final var dependencies        = new FeatureAdapter[count];
+            final var associationNames    = new String[count];
+            final var foreignerKeyIndices = new int[count][];
             /*
              * For each foreigner key to another table, append all columns of 
that foreigner key
              * and the name of the single feature property where the 
association will be stored.
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/PrimaryKey.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/PrimaryKey.java
index 8ace760ca5..5341444b43 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/PrimaryKey.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/PrimaryKey.java
@@ -18,6 +18,8 @@ package org.apache.sis.storage.sql.feature;
 
 import java.util.List;
 import java.util.Collection;
+import java.util.StringJoiner;
+import org.apache.sis.util.Classes;
 import org.apache.sis.util.privy.CollectionsExt;
 import org.apache.sis.util.privy.UnmodifiableArrayList;
 
@@ -105,4 +107,14 @@ abstract class PrimaryKey {
             return columns;
         }
     }
+
+    /**
+     * Returns a string representation of this primary key for debugging 
purposes.
+     */
+    @Override
+    public String toString() {
+        var buffer = new StringJoiner(", ", "(", ")");
+        getColumns().forEach(buffer::add);
+        return buffer + " as " + Classes.getShortName(valueClass);
+    }
 }
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 73bf3dd419..d2083beeee 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
@@ -107,8 +107,8 @@ final class QueryAnalyzer extends FeatureAnalyzer {
     @Override
     Relation[] getForeignerKeys(final Relation.Direction direction) throws 
SQLException, DataStoreException {
         final boolean isImport = (direction == Relation.Direction.IMPORT);
-        List<String> primaryKeyColumns = isImport ? new ArrayList<>() : null;
-        final List<Relation> relations = new ArrayList<>();
+        var primaryKeyColumns = isImport ? new ArrayList<String>() : null;
+        final var relations = new ArrayList<Relation>();
         for (final Map.Entry<TableReference, Map<String,Column>> entry : 
columnsPerTable.entrySet()) {
             final Set<String> columnNames = entry.getValue().keySet();
             final TableReference src = entry.getKey();
@@ -121,7 +121,7 @@ final class QueryAnalyzer extends FeatureAnalyzer {
                                               : 
analyzer.metadata.getExportedKeys(src.catalog, src.schema, src.table))
             {
                 if (reflect.next()) do {
-                    final Relation relation = new Relation(analyzer, 
direction, reflect);
+                    final var relation = new Relation(analyzer, direction, 
reflect);
                     if (columnNames.containsAll(relation.getOwnerColumns())) {
                         if (isImport) {
                             addForeignerKeys(relation);
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Relation.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Relation.java
index ae9e7dfd7a..8471b3ccbc 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Relation.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Relation.java
@@ -204,7 +204,7 @@ final class Relation extends TableReference {
               analyzer.getUniqueString(reflect, dir.table),
               analyzer.getUniqueString(reflect, Reflection.FK_NAME));
 
-        final Map<String,String> m = new LinkedHashMap<>();
+        final var m = new LinkedHashMap<String,String>();
         do {
             final String column = analyzer.getUniqueString(reflect, 
dir.column);
             if (m.put(column, analyzer.getUniqueString(reflect, 
dir.containerColumn)) != null) {
@@ -216,9 +216,16 @@ final class Relation extends TableReference {
                 break;
             }
         } while (table.equals(reflect.getString(dir.table)) &&                 
 // Table name is mandatory.
-                 Objects.equals(schema,  reflect.getString(dir.schema)) &&     
 // Schema and catalog may be null.
-                 Objects.equals(catalog, reflect.getString(dir.catalog)));
-
+                 Objects.equals(schema,   reflect.getString(dir.schema)) &&    
 // Schema and catalog may be null.
+                 Objects.equals(catalog,  reflect.getString(dir.catalog)) &&
+                 Objects.equals(freeText, 
reflect.getString(Reflection.FK_NAME)));
+        /*
+         * In above conditions, the comparison of `FK_NAME` is actually the 
only mandatory check.
+         * The "catalog.schema.table" comparaison is a paranoiac check added 
as a safety in case
+         * the foreigner key is null or empty in some JDBC implementations.  
Note that the table
+         * name is not a sufficient condition, because we could have more than 
one foreigner key
+         * referencing the same table.
+         */
         columns = CollectionsExt.compact(m);
         /*
          * If the foreigner key uses exactly one column, we can use the name 
of that column.
@@ -308,7 +315,7 @@ final class Relation extends TableReference {
              * relations declare different column order in their foreigner 
key. Note that the 'columns' map
              * is unmodifiable if its size is less than 2, and modifiable 
otherwise.
              */
-            final Map<String,String> copy = new HashMap<>(columns);
+            final var copy = new HashMap<String,String>(columns);
             columns.clear();
             for (String key : pkColumns) {
                 String value = key;
diff --git 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Table.java
 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Table.java
index f9f06ef535..7bb776d5cc 100644
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Table.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/Table.java
@@ -228,9 +228,7 @@ final class Table extends AbstractFeatureSet {
                      * have been set to association names. If 
`ClassCastException` occurs here, it is a bug
                      * in our object constructions.
                      */
-                    final FeatureAssociationRole association =
-                            (FeatureAssociationRole) 
featureType.getProperty(relation.propertyName);
-
+                    final var association = (FeatureAssociationRole) 
featureType.getProperty(relation.propertyName);
                     final Table table = 
tables.get(association.getValueType().getName());
                     if (table == null) {
                         throw new 
InternalDataStoreException(association.toString());
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 d31ceddfc2..2571c18b95 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
@@ -16,8 +16,6 @@
  */
 package org.apache.sis.storage.sql.feature;
 
-import java.util.Map;
-import java.util.List;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.sql.SQLException;
@@ -106,7 +104,7 @@ final class TableAnalyzer extends FeatureAnalyzer {
      */
     @Override
     final Relation[] getForeignerKeys(final Relation.Direction direction) 
throws SQLException, DataStoreException {
-        final List<Relation> relations = new ArrayList<>();
+        final var relations = new ArrayList<Relation>();
         final boolean isImport = (direction == Relation.Direction.IMPORT);
         try (ResultSet reflect = isImport ? 
analyzer.metadata.getImportedKeys(id.catalog, id.schema, id.table)
                                           : 
analyzer.metadata.getExportedKeys(id.catalog, id.schema, id.table))
@@ -153,11 +151,11 @@ final class TableAnalyzer extends FeatureAnalyzer {
          * Get all columns in advance because `completeIntrospection(…)`
          * needs to be invoked before to invoke `database.getMapping(column)`.
          */
-        final Map<String,Column> columns = new LinkedHashMap<>();
+        final var columns = new LinkedHashMap<String,Column>();
         final String quote = analyzer.metadata.getIdentifierQuoteString();
         try (ResultSet reflect = analyzer.metadata.getColumns(id.catalog, 
schemaEsc, tableEsc, null)) {
             while (reflect.next()) {
-                final Column column = new Column(analyzer, reflect, quote);
+                final var column = new Column(analyzer, reflect, quote);
                 if (columns.put(column.name, column) != null) {
                     throw duplicatedColumn(column);
                 }
@@ -170,7 +168,7 @@ final class TableAnalyzer extends FeatureAnalyzer {
         /*
          * Analyze the type of each column, which may be geometric as a 
consequence of above call.
          */
-        final List<Column> attributes = new ArrayList<>();
+        final var attributes = new ArrayList<Column>();
         for (final Column column : columns.values()) {
             if (createAttribute(column)) {
                 attributes.add(column);

Reply via email to