Site icon Java, SQL and jOOQ.

Database schema navigation in Java

An important part of jOOQ is jooq-meta, the database schema navigation module. This is used by the code generator to discover relevant schema objects. I was asked several times why I rolled my own instead of using other libraries, such as SchemaCrawler or SchemaSpy, and indeed it’s a pity I cannot rely on other stable third party products. Here are some thoughts on database schema navigation:

Standards

The SQL-92 standard defines how RDBMS should implement an INFORMATION_SCHEMA containing their dictionary tables. And indeed, some RDBMS do implement parts of the standard specification. These RDBMS ship with some implementation of the standard. Close to the standard Liberal interpretation of the standard Other RDBMS provide their own idea of dictionary tables. This is something very tricky for schema navigation tools like jOOQ, to get a hold of. The dictionary table landscape can be described like this (my biased opinion): Neat and well-documented dictionary tables Hard to understand, not well-documented dictionary tables

JDBC abstraction

The variety of dictionary tables seems to scream for standard abstraction. While the SQL-92 standard could in fact be implemented on most of these RDBMS, JDBC abstraction is even better. JDBC knows of the DatabaseMetaData object and allows for navigating database schemata easily. Unfortunately, every now and then, this API will throw a SQLFeatureNotSupportedException. There is no general rule about which JDBC driver implements how much of this API and when a workaround is needed. For jOOQ code generation, these facts make this API quite useless.

Other tools

There are some other tools in the open source world, as mentioned previously. Here are some drawbacks of using those tools in jOOQ: For more information, visit their sites:

jooq-meta

Because of the above reasons, jOOQ ships with its own database schema navigation: jooq-meta. This module can be used independently as an alternative to JDBC’s DatabaseMetaData, SchemaCrawler or SchemaSpy. jooq-meta uses jOOQ-crafted queries to navigate database meta-data, hence it is also part of the integration test suite. As an example, see how the Ingres foreign key relationships are navigated with jooq-meta:

Result<Record> result = create()
    .select(
        IirefConstraints.REF_CONSTRAINT_NAME.trim(),
        IirefConstraints.UNIQUE_CONSTRAINT_NAME.trim(),
        IirefConstraints.REF_TABLE_NAME.trim(),
        IiindexColumns.COLUMN_NAME.trim())
    .from(IICONSTRAINTS)
    .join(IIREF_CONSTRAINTS)
    .on(Iiconstraints.CONSTRAINT_NAME.equal(IirefConstraints.REF_CONSTRAINT_NAME))
    .and(Iiconstraints.SCHEMA_NAME.equal(IirefConstraints.REF_SCHEMA_NAME))
    .join(IICONSTRAINT_INDEXES)
    .on(Iiconstraints.CONSTRAINT_NAME.equal(IiconstraintIndexes.CONSTRAINT_NAME))
    .and(Iiconstraints.SCHEMA_NAME.equal(IiconstraintIndexes.SCHEMA_NAME))
    .join(IIINDEXES)
    .on(IiconstraintIndexes.INDEX_NAME.equal(Iiindexes.INDEX_NAME))
    .and(IiconstraintIndexes.SCHEMA_NAME.equal(Iiindexes.INDEX_OWNER))
    .join(IIINDEX_COLUMNS)
    .on(Iiindexes.INDEX_NAME.equal(IiindexColumns.INDEX_NAME))
    .and(Iiindexes.INDEX_OWNER.equal(IiindexColumns.INDEX_OWNER))
    .where(Iiconstraints.SCHEMA_NAME.equal(getSchemaName()))
    .and(Iiconstraints.CONSTRAINT_TYPE.equal("R"))
    .orderBy(
        IirefConstraints.REF_TABLE_NAME.asc(),
        IirefConstraints.REF_CONSTRAINT_NAME.asc(),
        IiindexColumns.KEY_SEQUENCE.asc())
    .fetch();

Conclusion

Once more it can be said that the world of RDBMS is very heterogeneous. Database abstraction in Java is established only to a certain degree in technologies such as JDBC, Hibernate/JPA, and third party libraries such as SchemaCrawler, SchemaSpy, and jooq-meta.
Exit mobile version