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 <[email protected]>
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);