diff --git a/jOOQ-meta/src/main/java/org/jooq/util/AbstractTableDefinition.java b/jOOQ-meta/src/main/java/org/jooq/util/AbstractTableDefinition.java index e5d8fd315e..b826fbe85e 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/AbstractTableDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/AbstractTableDefinition.java @@ -44,6 +44,7 @@ package org.jooq.util; import static org.jooq.impl.DSL.table; import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; import org.jooq.Record; @@ -65,9 +66,14 @@ implements TableDefinition { private UniqueKeyDefinition primaryKey; private boolean identityLoaded; private IdentityDefinition identity; + private TableDefinition parentTable; + private List childTables; public AbstractTableDefinition(SchemaDefinition schema, String name, String comment) { super(schema, name, comment); + + parentTable = null; + childTables = new ArrayList(); } @Override @@ -130,6 +136,20 @@ implements TableDefinition { return identity; } + public final void setParentTable(TableDefinition parentTable) { + this.parentTable = parentTable; + } + + @Override + public final TableDefinition getParentTable() { + return parentTable; + } + + @Override + public final List getChildTables() { + return childTables; + } + @Override public final Table getTable() { return table(getQualifiedName()); diff --git a/jOOQ-meta/src/main/java/org/jooq/util/TableDefinition.java b/jOOQ-meta/src/main/java/org/jooq/util/TableDefinition.java index 96d328c75c..8f99f66821 100644 --- a/jOOQ-meta/src/main/java/org/jooq/util/TableDefinition.java +++ b/jOOQ-meta/src/main/java/org/jooq/util/TableDefinition.java @@ -99,6 +99,16 @@ public interface TableDefinition extends Definition { */ IdentityDefinition getIdentity(); + /** + * Get the parent table if table inheritance is applicable. + */ + TableDefinition getParentTable(); + + /** + * Get the child tables if table inheritance is applicable. + */ + List getChildTables(); + /** * This TableDefinition as a {@link Table}. */ 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 b444f49fda..1a8070dc4c 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 @@ -44,6 +44,7 @@ package org.jooq.util.postgres; import static org.jooq.impl.DSL.count; import static org.jooq.impl.DSL.decode; import static org.jooq.impl.DSL.field; +import static org.jooq.impl.DSL.max; import static org.jooq.impl.DSL.name; import static org.jooq.impl.DSL.select; import static org.jooq.impl.DSL.selectOne; @@ -58,21 +59,28 @@ 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; import static org.jooq.util.postgres.information_schema.Tables.TABLE_CONSTRAINTS; +import static org.jooq.util.postgres.pg_catalog.Tables.PG_CLASS; import static org.jooq.util.postgres.pg_catalog.Tables.PG_ENUM; +import static org.jooq.util.postgres.pg_catalog.Tables.PG_INHERITS; import static org.jooq.util.postgres.pg_catalog.Tables.PG_NAMESPACE; import static org.jooq.util.postgres.pg_catalog.Tables.PG_TYPE; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.jooq.DSLContext; +import org.jooq.Name; import org.jooq.Record; import org.jooq.Record2; import org.jooq.Record4; +import org.jooq.Record5; import org.jooq.Result; import org.jooq.SQLDialect; import org.jooq.impl.DSL; +import org.jooq.tools.JooqLogger; import org.jooq.util.AbstractDatabase; import org.jooq.util.ArrayDefinition; import org.jooq.util.ColumnDefinition; @@ -93,6 +101,9 @@ import org.jooq.util.hsqldb.HSQLDBDatabase; import org.jooq.util.postgres.information_schema.tables.CheckConstraints; import org.jooq.util.postgres.information_schema.tables.Routines; import org.jooq.util.postgres.information_schema.tables.TableConstraints; +import org.jooq.util.postgres.pg_catalog.tables.PgClass; +import org.jooq.util.postgres.pg_catalog.tables.PgInherits; +import org.jooq.util.postgres.pg_catalog.tables.PgNamespace; /** * Postgres uses the ANSI default INFORMATION_SCHEMA, but unfortunately ships @@ -103,6 +114,8 @@ import org.jooq.util.postgres.information_schema.tables.TableConstraints; */ public class PostgresDatabase extends AbstractDatabase { + private static final JooqLogger log = JooqLogger.getLogger(PostgresDatabase.class); + @Override protected void loadPrimaryKeys(DefaultRelations relations) throws SQLException { for (Record record : fetchKeys("PRIMARY KEY")) { @@ -232,6 +245,7 @@ public class PostgresDatabase extends AbstractDatabase { @Override protected List getTables0() throws SQLException { List result = new ArrayList(); + Map map = new HashMap(); for (Record record : create() .select( @@ -248,7 +262,51 @@ public class PostgresDatabase extends AbstractDatabase { String name = record.getValue(TABLES.TABLE_NAME); String comment = ""; - result.add(new PostgresTableDefinition(schema, name, comment)); + PostgresTableDefinition t = new PostgresTableDefinition(schema, name, comment); + result.add(t); + map.put(name(schema.getName(), name), t); + } + + PgClass ct = PG_CLASS.as("ct"); + PgNamespace cn = PG_NAMESPACE.as("cn"); + PgInherits i = PG_INHERITS.as("i"); + PgClass pt = PG_CLASS.as("pt"); + PgNamespace pn = PG_NAMESPACE.as("pn"); + + for (Record5 inheritance : create() + .select( + cn.NSPNAME, + ct.RELNAME, + pn.NSPNAME, + pt.RELNAME, + max(i.INHSEQNO).over().partitionBy(i.INHRELID).as("m") + ) + .from(ct) + .join(cn).on("{0} = {1}.oid", ct.RELNAMESPACE, cn) + .join(i).on("{0} = {1}.oid", i.INHRELID, ct) + .join(pt).on("{0} = {1}.oid", i.INHPARENT, pt) + .join(pn).on("{0} = {1}.oid", pt.RELNAMESPACE, pn) + .fetch()) { + + Name child = name(inheritance.value1(), inheritance.value2()); + Name parent = name(inheritance.value3(), inheritance.value4()); + + if (inheritance.value5() > 1) { + log.info("Multiple inheritance", + "Multiple inheritance is not supported by jOOQ: " + + child + + " inherits from " + + parent); + } + else { + PostgresTableDefinition childTable = map.get(child); + PostgresTableDefinition parentTable = map.get(parent); + + if (childTable != null && parentTable != null) { + childTable.setParentTable(parentTable); + parentTable.getChildTables().add(childTable); + } + } } return result; diff --git a/jOOQ-test/src/org/jooq/test/PostgresTest.java b/jOOQ-test/src/org/jooq/test/PostgresTest.java index d2950de233..9ce38bbf3e 100644 --- a/jOOQ-test/src/org/jooq/test/PostgresTest.java +++ b/jOOQ-test/src/org/jooq/test/PostgresTest.java @@ -59,7 +59,7 @@ import static org.jooq.test.postgres.generatedclasses.Tables.T_DATES; import static org.jooq.test.postgres.generatedclasses.Tables.T_EXOTIC_TYPES; import static org.jooq.test.postgres.generatedclasses.Tables.T_IDENTITY; import static org.jooq.test.postgres.generatedclasses.Tables.T_IDENTITY_PK; -import static org.jooq.test.postgres.generatedclasses.Tables.T_INHERITANCE_CITIES; +import static org.jooq.test.postgres.generatedclasses.Tables.T_INHERITANCE_1; import static org.jooq.test.postgres.generatedclasses.Tables.T_PG_EXTENSIONS; import static org.jooq.test.postgres.generatedclasses.Tables.T_TRIGGERS; import static org.jooq.test.postgres.generatedclasses.Tables.T_UNSIGNED; @@ -1065,7 +1065,7 @@ public class PostgresTest extends jOOQAbstractTest< @Test public void testPostgresOnlyClause() throws Exception { - assertEquals(3, create().fetchCount(selectOne().from(T_INHERITANCE_CITIES))); - assertEquals(2, create().fetchCount(selectOne().from(only(T_INHERITANCE_CITIES)))); + assertEquals(3, create().fetchCount(selectOne().from(T_INHERITANCE_1))); + assertEquals(2, create().fetchCount(selectOne().from(only(T_INHERITANCE_1)))); } } diff --git a/jOOQ-test/src/org/jooq/test/postgres/create.sql b/jOOQ-test/src/org/jooq/test/postgres/create.sql index 6d35f502dd..cb873285a6 100644 --- a/jOOQ-test/src/org/jooq/test/postgres/create.sql +++ b/jOOQ-test/src/org/jooq/test/postgres/create.sql @@ -64,8 +64,11 @@ DROP TABLE IF EXISTS t_booleans/ DROP TABLE IF EXISTS t_identity/ DROP TABLE IF EXISTS t_identity_pk/ DROP TABLE IF EXISTS t_pg_extensions/ -DROP TABLE IF EXISTS t_inheritance_capitals/ -DROP TABLE IF EXISTS t_inheritance_cities/ +DROP TABLE IF EXISTS t_inheritance_1_all/ +DROP TABLE IF EXISTS t_inheritance_1_2_1/ +DROP TABLE IF EXISTS t_inheritance_1_2/ +DROP TABLE IF EXISTS t_inheritance_1_1/ +DROP TABLE IF EXISTS t_inheritance_1/ DROP TYPE IF EXISTS u_address_type/ DROP TYPE IF EXISTS u_street_type/ @@ -110,16 +113,29 @@ CREATE TYPE u_address_type AS ( ) / -CREATE TABLE t_inheritance_cities ( - name text, - population int, - altitude int +CREATE TABLE t_inheritance_1 ( + text_1 text ) / -CREATE TABLE t_inheritance_capitals ( - state char(2) -) INHERITS (t_inheritance_cities) +CREATE TABLE t_inheritance_1_1 ( + text_1_1 text +) INHERITS (t_inheritance_1) +/ + +CREATE TABLE t_inheritance_1_2 ( + text_1_2 text +) INHERITS (t_inheritance_1) +/ + +CREATE TABLE t_inheritance_1_2_1 ( + text_1_2_1 text +) INHERITS (t_inheritance_1_2) +/ + +CREATE TABLE t_inheritance_all ( + text_1_all text +) INHERITS (t_inheritance_1_1, t_inheritance_1_2) / CREATE TABLE t_pg_extensions ( diff --git a/jOOQ-test/src/org/jooq/test/postgres/reset.sql b/jOOQ-test/src/org/jooq/test/postgres/reset.sql index 27c7f7746b..b051cb9613 100644 --- a/jOOQ-test/src/org/jooq/test/postgres/reset.sql +++ b/jOOQ-test/src/org/jooq/test/postgres/reset.sql @@ -54,6 +54,6 @@ INSERT INTO t_arrays VALUES (2, '{}', '{}', '{}', '{}', '{}', '{}')/ INSERT INTO t_arrays VALUES (3, '{"a"}', '{1}', ARRAY[TO_DATE('1981-07-10', 'YYYY-MM-DD')], ARRAY[ROW('Downing Street', '10', null, E'\\x6969')]::u_street_type[], '{"England"}', ARRAY[ARRAY[1]])/ INSERT INTO t_arrays VALUES (4, '{"a", "b"}', '{1, 2}', ARRAY[TO_DATE('1981-07-10', 'YYYY-MM-DD'), TO_DATE('2000-01-01', 'YYYY-MM-DD')], ARRAY[ROW('Downing Street', '10', '{}', E'\\x6969'), ROW('Bahnhofstrasse', '12', '{1, 2}', E'\\x6969')]::u_street_type[], '{"England", "Germany"}', ARRAY[ARRAY[1], ARRAY[2]])/ -INSERT INTO t_inheritance_capitals VALUES ('Zurich', 396389, 408, 'ZH')/ -INSERT INTO t_inheritance_cities VALUES ('Winterthur', 103075, 439)/ -INSERT INTO t_inheritance_cities VALUES ('Uster', 32577, 464)/ \ No newline at end of file +INSERT INTO t_inheritance_1_1 VALUES ('1', '1')/ +INSERT INTO t_inheritance_1 VALUES ('2')/ +INSERT INTO t_inheritance_1 VALUES ('3')/ \ No newline at end of file