diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/AbstractTableDefinition.java b/jOOQ-meta/src/main/java/org/jooq/meta/AbstractTableDefinition.java index c3a9556667..64a232d4d6 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/AbstractTableDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/AbstractTableDefinition.java @@ -99,6 +99,15 @@ implements TableDefinition { return getDatabase().getRelations().getUniqueKeys(this); } + @Override + public final UniqueKeyDefinition getUniqueKey(String name) { + for (UniqueKeyDefinition uk : getUniqueKeys()) + if (uk.getInputName().equals(name)) + return uk; + + return null; + } + @Override public final List getForeignKeys() { return getDatabase().getRelations().getForeignKeys(this); diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/DefaultForeignKeyDefinition.java b/jOOQ-meta/src/main/java/org/jooq/meta/DefaultForeignKeyDefinition.java index 1c03fecd71..1b25359ea9 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/DefaultForeignKeyDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/DefaultForeignKeyDefinition.java @@ -44,18 +44,20 @@ import java.util.Set; public class DefaultForeignKeyDefinition extends AbstractConstraintDefinition implements ForeignKeyDefinition { - private final List keyColumns; - private final UniqueKeyDefinition uniqueKey; + private final List fkColumns; + private final List ukColumns; + private final UniqueKeyDefinition uk; public DefaultForeignKeyDefinition(SchemaDefinition schema, String name, TableDefinition table, UniqueKeyDefinition uniqueKey) { this(schema, name, table, uniqueKey, true); } - public DefaultForeignKeyDefinition(SchemaDefinition schema, String name, TableDefinition table, UniqueKeyDefinition uniqueKey, boolean enforced) { + public DefaultForeignKeyDefinition(SchemaDefinition schema, String name, TableDefinition table, UniqueKeyDefinition uk, boolean enforced) { super(schema, table, name, enforced); - this.keyColumns = new ArrayList<>(); - this.uniqueKey = uniqueKey; + this.fkColumns = new ArrayList<>(); + this.ukColumns = new ArrayList<>(); + this.uk = uk; } @Override @@ -65,22 +67,22 @@ public class DefaultForeignKeyDefinition extends AbstractConstraintDefinition im @Override public List getKeyColumns() { - return keyColumns; + return fkColumns; } @Override public UniqueKeyDefinition getReferencedKey() { - return uniqueKey; + return uk; } @Override public TableDefinition getReferencedTable() { - return uniqueKey.getTable(); + return uk.getTable(); } @Override public List getReferencedColumns() { - return uniqueKey.getKeyColumns(); + return ukColumns; } @Override diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/DefaultRelations.java b/jOOQ-meta/src/main/java/org/jooq/meta/DefaultRelations.java index 6bcf596a31..ed9b77c60a 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/DefaultRelations.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/DefaultRelations.java @@ -39,6 +39,7 @@ package org.jooq.meta; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; @@ -189,14 +190,54 @@ public class DefaultRelations implements Relations { ColumnDefinition foreignKeyColumn, String uniqueKeyName, TableDefinition uniqueKeyTable, - boolean enforced) { + boolean enforced + ) { + UniqueKeyDefinition uk = uniqueKeys.get(key(uniqueKeyTable, uniqueKeyName)); + Key key = key(foreignKeyTable, foreignKeyName); + if (uk == null) { + log.info("Ignoring foreign key", uniqueKeyName + " (unique key unavailable)"); + // [#7826] Prevent incomplete keys from being generated + if (foreignKeyTable != null) { + + incompleteKeys.add(key); + foreignKeys.remove(key); + } + + return; + } + + addForeignKey(foreignKeyName, foreignKeyTable, foreignKeyColumn, uniqueKeyName, uniqueKeyTable, getNextUkColumn(key, uk), enforced); + } + + private Map nextUkColumnIndex = new HashMap<>(); + + private ColumnDefinition getNextUkColumn(Key key, UniqueKeyDefinition uk) { + Integer index = nextUkColumnIndex.get(key); + + if (index == null) + nextUkColumnIndex.put(key, index = 0); + else + nextUkColumnIndex.put(key, index = index + 1); + + return uk.getKeyColumns().get(index); + } + + public void addForeignKey( + String foreignKeyName, + TableDefinition foreignKeyTable, + ColumnDefinition foreignKeyColumn, + String uniqueKeyName, + TableDefinition uniqueKeyTable, + ColumnDefinition uniqueKeyColumn, + boolean enforced + ) { // [#2718] Column exclusions may hit foreign key references. Ignore // such foreign keys Key key = key(foreignKeyTable, foreignKeyName); - if (foreignKeyColumn == null) { - log.info("Ignoring foreign key", foreignKeyColumn + " (column unavailable)"); + if (foreignKeyColumn == null || uniqueKeyColumn == null) { + log.info("Ignoring foreign key", foreignKeyColumn + " referencing " + uniqueKeyColumn + " (column unavailable)"); // [#7826] Prevent incomplete keys from being generated if (foreignKeyTable != null) { @@ -213,11 +254,11 @@ public class DefaultRelations implements Relations { // [#1134] Prevent NPE's when a foreign key references a unique key // from another schema if (uniqueKeyTable == null) { - log.info("Ignoring foreign key", foreignKeyName + " (" + foreignKeyColumn + ") referencing " + uniqueKeyName + " references a schema out of scope for jooq-meta: " + uniqueKeyTable); + log.info("Ignoring foreign key", foreignKeyName + " (" + foreignKeyColumn + ") referencing " + uniqueKeyName + " (" + uniqueKeyColumn + ") references a schema out of scope for jooq-meta: " + uniqueKeyTable); return; } - log.info("Adding foreign key", foreignKeyName + " (" + foreignKeyColumn + ") referencing " + uniqueKeyName); + log.info("Adding foreign key", foreignKeyName + " (" + foreignKeyColumn + ") referencing " + uniqueKeyName + " (" + uniqueKeyColumn + ")"); ForeignKeyDefinition foreignKey = foreignKeys.get(key); @@ -226,15 +267,23 @@ public class DefaultRelations implements Relations { // If the unique key is not loaded, ignore this foreign key if (uniqueKey != null) { - foreignKey = new DefaultForeignKeyDefinition(foreignKeyColumn.getSchema(), foreignKeyName, foreignKeyColumn.getContainer(), uniqueKey, enforced); - foreignKeys.put(key, foreignKey); + foreignKey = new DefaultForeignKeyDefinition( + foreignKeyColumn.getSchema(), + foreignKeyName, + foreignKeyColumn.getContainer(), + uniqueKey, + enforced + ); + foreignKeys.put(key, foreignKey); uniqueKey.getForeignKeys().add(foreignKey); } } - if (foreignKey != null) + if (foreignKey != null) { foreignKey.getKeyColumns().add(foreignKeyColumn); + foreignKey.getReferencedColumns().add(uniqueKeyColumn); + } } public void addCheckConstraint(TableDefinition table, CheckConstraintDefinition constraint) { diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/TableDefinition.java b/jOOQ-meta/src/main/java/org/jooq/meta/TableDefinition.java index 57eef537e5..399d09c600 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/TableDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/TableDefinition.java @@ -90,6 +90,11 @@ public interface TableDefinition extends Definition { */ List getUniqueKeys(); + /** + * Get the unique key for this table by name. + */ + UniqueKeyDefinition getUniqueKey(String name); + /** * Get the foreign keys for this table. */ diff --git a/jOOQ-meta/src/main/java/org/jooq/meta/h2/H2Database.java b/jOOQ-meta/src/main/java/org/jooq/meta/h2/H2Database.java index cb5817b3b2..d6ae95a95a 100644 --- a/jOOQ-meta/src/main/java/org/jooq/meta/h2/H2Database.java +++ b/jOOQ-meta/src/main/java/org/jooq/meta/h2/H2Database.java @@ -287,6 +287,7 @@ public class H2Database extends AbstractDatabase { CrossReferences.FKTABLE_NAME, CrossReferences.FKTABLE_SCHEMA, CrossReferences.FKCOLUMN_NAME, + CrossReferences.PKCOLUMN_NAME, Constraints.CONSTRAINT_NAME, Constraints.TABLE_NAME, Constraints.CONSTRAINT_SCHEMA) @@ -314,6 +315,7 @@ public class H2Database extends AbstractDatabase { String foreignKeyColumn = record.get(CrossReferences.FKCOLUMN_NAME); String uniqueKey = record.get(Constraints.CONSTRAINT_NAME); String uniqueKeyTableName = record.get(Constraints.TABLE_NAME); + String uniqueKeyColumn = record.get(CrossReferences.PKCOLUMN_NAME); TableDefinition foreignKeyTable = getTable(foreignKeySchema, foreignKeyTableName); TableDefinition uniqueKeyTable = getTable(uniqueKeySchema, uniqueKeyTableName); @@ -324,7 +326,9 @@ public class H2Database extends AbstractDatabase { foreignKeyTable, foreignKeyTable.getColumn(foreignKeyColumn), uniqueKey, - uniqueKeyTable + uniqueKeyTable, + uniqueKeyTable.getColumn(uniqueKeyColumn), + true ); } }