From 656a1174a8fc07cf43a3456fe2d392cf81254c8c Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 11 Aug 2014 10:57:50 +0200 Subject: [PATCH] [#3520] Duplicate column information in foreign key references for foreign keys that share the same name in different tables --- .../jooq/util/postgres/PostgresDatabase.java | 43 ++++++++----------- .../test/java/org/jooq/test/PostgresTest.java | 25 +++++++++++ .../test/postgres/generatedclasses/Keys.java | 4 +- 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/jOOQ-meta/src/main/java/org/jooq/util/postgres/PostgresDatabase.java b/jOOQ-meta/src/main/java/org/jooq/util/postgres/PostgresDatabase.java index 76fa538692..7d0f10ff23 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/postgres/PostgresDatabase.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/postgres/PostgresDatabase.java @@ -56,7 +56,6 @@ import static org.jooq.util.postgres.information_schema.Tables.ATTRIBUTES; import static org.jooq.util.postgres.information_schema.Tables.CHECK_CONSTRAINTS; import static org.jooq.util.postgres.information_schema.Tables.KEY_COLUMN_USAGE; import static org.jooq.util.postgres.information_schema.Tables.PARAMETERS; -import static org.jooq.util.postgres.information_schema.Tables.REFERENTIAL_CONSTRAINTS; import static org.jooq.util.postgres.information_schema.Tables.ROUTINES; import static org.jooq.util.postgres.information_schema.Tables.SEQUENCES; import static org.jooq.util.postgres.information_schema.Tables.TABLES; @@ -177,34 +176,26 @@ public class PostgresDatabase extends AbstractDatabase { @Override protected void loadForeignKeys(DefaultRelations relations) throws SQLException { - Result result = create() - .select( - REFERENTIAL_CONSTRAINTS.UNIQUE_CONSTRAINT_NAME, - REFERENTIAL_CONSTRAINTS.UNIQUE_CONSTRAINT_SCHEMA, - KEY_COLUMN_USAGE.CONSTRAINT_NAME, - KEY_COLUMN_USAGE.TABLE_SCHEMA, - KEY_COLUMN_USAGE.TABLE_NAME, - KEY_COLUMN_USAGE.COLUMN_NAME) - .from(REFERENTIAL_CONSTRAINTS) - .join(KEY_COLUMN_USAGE) - .on(KEY_COLUMN_USAGE.CONSTRAINT_SCHEMA.equal(REFERENTIAL_CONSTRAINTS.CONSTRAINT_SCHEMA)) - .and(KEY_COLUMN_USAGE.CONSTRAINT_NAME.equal(REFERENTIAL_CONSTRAINTS.CONSTRAINT_NAME)) - .where(KEY_COLUMN_USAGE.TABLE_SCHEMA.in(getInputSchemata())) - .orderBy( - KEY_COLUMN_USAGE.TABLE_SCHEMA.asc(), - KEY_COLUMN_USAGE.TABLE_NAME.asc(), - KEY_COLUMN_USAGE.CONSTRAINT_NAME.asc(), - KEY_COLUMN_USAGE.ORDINAL_POSITION.asc()) - .fetch(); + + // [#3520] PostgreSQL INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS contains incomplete information about foreign keys + // The (CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME) tuple is non-unique, in case two tables share the + // same CONSTRAINT_NAME. + // The JDBC driver implements this correctly through the pg_catalog, although the sorting and column name casing is wrong, too. + Result result = create() + .fetch(getConnection().getMetaData().getExportedKeys(null, null, null)) + .sortAsc("key_seq") + .sortAsc("fk_name") + .sortAsc("fktable_name") + .sortAsc("fktable_schem"); for (Record record : result) { - SchemaDefinition foreignKeySchema = getSchema(record.getValue(KEY_COLUMN_USAGE.TABLE_SCHEMA)); - SchemaDefinition uniqueKeySchema = getSchema(record.getValue(REFERENTIAL_CONSTRAINTS.UNIQUE_CONSTRAINT_SCHEMA)); + SchemaDefinition foreignKeySchema = getSchema(record.getValue("fktable_schem", String.class)); + SchemaDefinition uniqueKeySchema = getSchema(record.getValue("pktable_schem", String.class)); - String foreignKey = record.getValue(KEY_COLUMN_USAGE.CONSTRAINT_NAME); - String foreignKeyTable = record.getValue(KEY_COLUMN_USAGE.TABLE_NAME); - String foreignKeyColumn = record.getValue(KEY_COLUMN_USAGE.COLUMN_NAME); - String uniqueKey = record.getValue(REFERENTIAL_CONSTRAINTS.UNIQUE_CONSTRAINT_NAME); + String foreignKey = record.getValue("fk_name", String.class); + String foreignKeyTable = record.getValue("fktable_name", String.class); + String foreignKeyColumn = record.getValue("fkcolumn_name", String.class); + String uniqueKey = record.getValue("pk_name", String.class); TableDefinition referencingTable = getTable(foreignKeySchema, foreignKeyTable); diff --git a/jOOQ-test/src/test/java/org/jooq/test/PostgresTest.java b/jOOQ-test/src/test/java/org/jooq/test/PostgresTest.java index 21b1441d95..8135743f4d 100644 --- a/jOOQ-test/src/test/java/org/jooq/test/PostgresTest.java +++ b/jOOQ-test/src/test/java/org/jooq/test/PostgresTest.java @@ -59,6 +59,8 @@ import static org.jooq.test.postgres.generatedclasses.Tables.T_639_NUMBERS_TABLE import static org.jooq.test.postgres.generatedclasses.Tables.T_725_LOB_TEST; import static org.jooq.test.postgres.generatedclasses.Tables.T_785; import static org.jooq.test.postgres.generatedclasses.Tables.T_959; +import static org.jooq.test.postgres.generatedclasses.Tables.T_986_1; +import static org.jooq.test.postgres.generatedclasses.Tables.T_986_2; import static org.jooq.test.postgres.generatedclasses.Tables.T_ARRAYS; import static org.jooq.test.postgres.generatedclasses.Tables.T_AUTHOR; import static org.jooq.test.postgres.generatedclasses.Tables.T_BOOK; @@ -76,6 +78,7 @@ import static org.jooq.test.postgres.generatedclasses.Tables.T_UNSIGNED; import static org.jooq.test.postgres.generatedclasses.Tables.V_AUTHOR; import static org.jooq.test.postgres.generatedclasses.Tables.V_BOOK; import static org.jooq.test.postgres.generatedclasses.Tables.V_LIBRARY; +import static org.jooq.test.postgres.generatedclasses.Tables.X_UNUSED; import static org.jooq.util.postgres.PostgresDSL.arrayAppend; import static org.jooq.util.postgres.PostgresDSL.arrayCat; import static org.jooq.util.postgres.PostgresDSL.arrayPrepend; @@ -149,6 +152,8 @@ import org.jooq.test.postgres.generatedclasses.tables.records.T_3111Record; import org.jooq.test.postgres.generatedclasses.tables.records.T_639NumbersTableRecord; import org.jooq.test.postgres.generatedclasses.tables.records.T_725LobTestRecord; import org.jooq.test.postgres.generatedclasses.tables.records.T_785Record; +import org.jooq.test.postgres.generatedclasses.tables.records.T_986_1Record; +import org.jooq.test.postgres.generatedclasses.tables.records.T_986_2Record; import org.jooq.test.postgres.generatedclasses.tables.records.VLibraryRecord; import org.jooq.test.postgres.generatedclasses.tables.records.XUnusedRecord; import org.jooq.test.postgres.generatedclasses.udt.UAddressType; @@ -1334,4 +1339,24 @@ public class PostgresTest extends jOOQAbstractTest< create().delete(T_3111).execute(); } } + + @Test + public void testPostgresMetaReferencesWithSameNameForeignKey() { + + // [#986] [#3520] Be sure that shared foreign key names do not produce any irregular behaviour + List> r1 = T_986_1.getReferencesTo(X_UNUSED); + List> r2 = T_986_2.getReferencesTo(X_UNUSED); + + assertEquals(1, r1.size()); + assertEquals(1, r2.size()); + + assertEquals(T_986_1, r1.get(0).getTable()); + assertEquals(T_986_2, r2.get(0).getTable()); + + assertEquals(asList(T_986_1.REF), r1.get(0).getFields()); + assertEquals(asList(T_986_2.REF), r2.get(0).getFields()); + + assertEquals(0, (int) create().selectCount().from(T_986_1.join(X_UNUSED).onKey()).fetchOne(0, int.class)); + assertEquals(0, (int) create().selectCount().from(T_986_2.join(X_UNUSED).onKey()).fetchOne(0, int.class)); + } } diff --git a/jOOQ-test/src/test/java/org/jooq/test/postgres/generatedclasses/Keys.java b/jOOQ-test/src/test/java/org/jooq/test/postgres/generatedclasses/Keys.java index c959c00ab3..f0c8354d87 100644 --- a/jOOQ-test/src/test/java/org/jooq/test/postgres/generatedclasses/Keys.java +++ b/jOOQ-test/src/test/java/org/jooq/test/postgres/generatedclasses/Keys.java @@ -101,8 +101,8 @@ public class Keys { } private static class ForeignKeys0 extends org.jooq.impl.AbstractKeys { - public static final org.jooq.ForeignKey T_986_1__FK_986 = createForeignKey(org.jooq.test.postgres.generatedclasses.Keys.UK_X_UNUSED_ID, org.jooq.test.postgres.generatedclasses.tables.T_986_1.T_986_1, org.jooq.test.postgres.generatedclasses.tables.T_986_1.T_986_1.REF, org.jooq.test.postgres.generatedclasses.tables.T_986_1.T_986_1.REF); - public static final org.jooq.ForeignKey T_986_2__FK_986 = createForeignKey(org.jooq.test.postgres.generatedclasses.Keys.UK_X_UNUSED_ID, org.jooq.test.postgres.generatedclasses.tables.T_986_2.T_986_2, org.jooq.test.postgres.generatedclasses.tables.T_986_2.T_986_2.REF, org.jooq.test.postgres.generatedclasses.tables.T_986_2.T_986_2.REF); + public static final org.jooq.ForeignKey T_986_1__FK_986 = createForeignKey(org.jooq.test.postgres.generatedclasses.Keys.UK_X_UNUSED_ID, org.jooq.test.postgres.generatedclasses.tables.T_986_1.T_986_1, org.jooq.test.postgres.generatedclasses.tables.T_986_1.T_986_1.REF); + public static final org.jooq.ForeignKey T_986_2__FK_986 = createForeignKey(org.jooq.test.postgres.generatedclasses.Keys.UK_X_UNUSED_ID, org.jooq.test.postgres.generatedclasses.tables.T_986_2.T_986_2, org.jooq.test.postgres.generatedclasses.tables.T_986_2.T_986_2.REF); public static final org.jooq.ForeignKey T_BOOK__FK_T_BOOK_AUTHOR_ID = createForeignKey(org.jooq.test.postgres.generatedclasses.Keys.PK_T_AUTHOR, org.jooq.test.postgres.generatedclasses.tables.TBook.T_BOOK, org.jooq.test.postgres.generatedclasses.tables.TBook.T_BOOK.AUTHOR_ID); public static final org.jooq.ForeignKey T_BOOK__FK_T_BOOK_CO_AUTHOR_ID = createForeignKey(org.jooq.test.postgres.generatedclasses.Keys.PK_T_AUTHOR, org.jooq.test.postgres.generatedclasses.tables.TBook.T_BOOK, org.jooq.test.postgres.generatedclasses.tables.TBook.T_BOOK.CO_AUTHOR_ID); public static final org.jooq.ForeignKey T_BOOK__FK_T_BOOK_LANGUAGE_ID = createForeignKey(org.jooq.test.postgres.generatedclasses.Keys.PK_T_LANGUAGE, org.jooq.test.postgres.generatedclasses.tables.TBook.T_BOOK, org.jooq.test.postgres.generatedclasses.tables.TBook.T_BOOK.LANGUAGE_ID);