diff --git a/jOOQ/src/main/java/org/jooq/Configuration.java b/jOOQ/src/main/java/org/jooq/Configuration.java index 5c7594205b..ec11678e77 100644 --- a/jOOQ/src/main/java/org/jooq/Configuration.java +++ b/jOOQ/src/main/java/org/jooq/Configuration.java @@ -254,6 +254,11 @@ public interface Configuration extends Serializable { */ ConnectionProvider connectionProvider(); + /** + * Get this configuration's underlying meta provider. + */ + MetaProvider metaProvider(); + /** * Get this configuration's underlying executor provider. *

@@ -431,6 +436,18 @@ public interface Configuration extends Serializable { */ Configuration set(ConnectionProvider newConnectionProvider); + /** + * Change this configuration to hold a new meta provider. + *

+ * This method is not thread-safe and should not be used in globally + * available Configuration objects. + * + * @param newMetaProvider The new meta provider to be contained in the + * changed configuration. + * @return The changed configuration. + */ + Configuration set(MetaProvider newMetaProvider); + /** * Change this configuration to hold a new executor provider. *

@@ -776,6 +793,15 @@ public interface Configuration extends Serializable { */ Configuration derive(ConnectionProvider newConnectionProvider); + /** + * Create a derived configuration from this one, with a new meta provider. + * + * @param newMetaProvider The new meta provider to be contained in the + * derived configuration. + * @return The derived configuration. + */ + Configuration derive(MetaProvider newMetaProvider); + /** * Create a derived configuration from this one, with a new executor. *

diff --git a/jOOQ/src/main/java/org/jooq/DSLContext.java b/jOOQ/src/main/java/org/jooq/DSLContext.java index 21b77c4d59..1508ad0f6a 100644 --- a/jOOQ/src/main/java/org/jooq/DSLContext.java +++ b/jOOQ/src/main/java/org/jooq/DSLContext.java @@ -65,6 +65,7 @@ import static org.jooq.SQLDialect.SQLITE; import java.math.BigInteger; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -250,7 +251,27 @@ public interface DSLContext extends Scope , AutoCloseable { Meta meta(); /** - * Access the databse meta data from its serialised form. + * Access the database meta data from JDBC {@link DatabaseMetaData}. + */ + Meta meta(DatabaseMetaData meta); + + /** + * Access the database meta data from catalog information. + */ + Meta meta(Catalog... catalogs); + + /** + * Access the database meta data from schema information. + */ + Meta meta(Schema... schemas); + + /** + * Access the database meta data from table information. + */ + Meta meta(Table... tables); + + /** + * Access the database meta data from an JAXB-annotated meta model. */ Meta meta(InformationSchema schema); diff --git a/jOOQ/src/main/java/org/jooq/MetaProvider.java b/jOOQ/src/main/java/org/jooq/MetaProvider.java new file mode 100644 index 0000000000..c08b81b70a --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/MetaProvider.java @@ -0,0 +1,60 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: http://www.jooq.org/licenses + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq; + +import java.sql.DatabaseMetaData; + +/** + * An SPI that can produce dynamic catalog, schema, table meta data information. + *

+ * The default implementation will produce information based on + * {@link DatabaseMetaData} obtained from the enclosing + * {@link Configuration#connectionProvider()}. + * + * @author Lukas Eder + */ + +@FunctionalInterface + +public interface MetaProvider { + + /** + * Provide meta data information. + */ + Meta provide(); +} diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java index e85288a36b..b31581b131 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java @@ -64,6 +64,7 @@ import org.jooq.DiagnosticsListenerProvider; import org.jooq.ExecuteListener; import org.jooq.ExecuteListenerProvider; import org.jooq.ExecutorProvider; +import org.jooq.MetaProvider; import org.jooq.Record; import org.jooq.RecordListener; import org.jooq.RecordListenerProvider; @@ -109,6 +110,7 @@ public class DefaultConfiguration implements Configuration { // These objects may be user defined and thus not necessarily serialisable private transient ConnectionProvider connectionProvider; + private transient MetaProvider metaProvider; private transient ExecutorProvider executorProvider; private transient TransactionProvider transactionProvider; private transient RecordMapperProvider recordMapperProvider; @@ -457,6 +459,7 @@ public class DefaultConfiguration implements Configuration { { this( connectionProvider, + null, executorProvider, transactionProvider, recordMapperProvider, @@ -511,6 +514,7 @@ public class DefaultConfiguration implements Configuration { { this( connectionProvider, + null, executorProvider, transactionProvider, recordMapperProvider, @@ -540,6 +544,7 @@ public class DefaultConfiguration implements Configuration { */ DefaultConfiguration( ConnectionProvider connectionProvider, + MetaProvider metaProvider, ExecutorProvider executorProvider, TransactionProvider transactionProvider, RecordMapperProvider recordMapperProvider, @@ -558,6 +563,7 @@ public class DefaultConfiguration implements Configuration { Map data) { set(connectionProvider); + set(metaProvider); set(executorProvider); set(transactionProvider); set(recordMapperProvider); @@ -611,6 +617,31 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(ConnectionProvider newConnectionProvider) { return new DefaultConfiguration( newConnectionProvider, + metaProvider, + executorProvider, + transactionProvider, + recordMapperProvider, + recordUnmapperProvider, + recordListenerProviders, + executeListenerProviders, + visitListenerProviders, + transactionListenerProviders, + diagnosticsListenerProviders, + converterProvider, + + clock, + + dialect, + settings, + data + ); + } + + @Override + public final Configuration derive(MetaProvider newMetaProvider) { + return new DefaultConfiguration( + connectionProvider, + newMetaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -639,6 +670,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(ExecutorProvider newExecutorProvider) { return new DefaultConfiguration( connectionProvider, + metaProvider, newExecutorProvider, transactionProvider, recordMapperProvider, @@ -662,6 +694,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(TransactionProvider newTransactionProvider) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, newTransactionProvider, recordMapperProvider, @@ -690,6 +723,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(RecordMapperProvider newRecordMapperProvider) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, newRecordMapperProvider, @@ -718,6 +752,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(RecordUnmapperProvider newRecordUnmapperProvider) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -746,6 +781,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(RecordListenerProvider... newRecordListenerProviders) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -774,6 +810,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(ExecuteListenerProvider... newExecuteListenerProviders) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -802,6 +839,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(VisitListenerProvider... newVisitListenerProviders) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -830,6 +868,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(TransactionListenerProvider... newTransactionListenerProviders) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -858,6 +897,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(DiagnosticsListenerProvider... newDiagnosticsListenerProviders) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -881,6 +921,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(ConverterProvider newConverterProvider) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -905,6 +946,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(Clock newClock) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -927,6 +969,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(SQLDialect newDialect) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -950,6 +993,7 @@ public class DefaultConfiguration implements Configuration { public final Configuration derive(Settings newSettings) { return new DefaultConfiguration( connectionProvider, + metaProvider, executorProvider, transactionProvider, recordMapperProvider, @@ -1001,6 +1045,12 @@ public class DefaultConfiguration implements Configuration { return this; } + @Override + public final Configuration set(MetaProvider newMetaProvider) { + this.metaProvider = newMetaProvider; + return this; + } + @Override public final Configuration set(Executor newExecutor) { return set(new ExecutorWrapper(newExecutor)); @@ -1268,6 +1318,13 @@ public class DefaultConfiguration implements Configuration { return transactional == null ? connectionProvider : transactional; } + @Override + public final MetaProvider metaProvider() { + return metaProvider != null + ? metaProvider + : new DefaultMetaProvider(this); + } + @Override public final ExecutorProvider executorProvider() { return executorProvider != null @@ -1405,6 +1462,9 @@ public class DefaultConfiguration implements Configuration { oos.writeObject(connectionProvider instanceof Serializable ? connectionProvider : null); + oos.writeObject(metaProvider instanceof Serializable + ? metaProvider + : null); oos.writeObject(transactionProvider instanceof Serializable ? transactionProvider : null); @@ -1456,6 +1516,7 @@ public class DefaultConfiguration implements Configuration { ois.defaultReadObject(); connectionProvider = (ConnectionProvider) ois.readObject(); + metaProvider = (MetaProvider) ois.readObject(); transactionProvider = (TransactionProvider) ois.readObject(); recordMapperProvider = (RecordMapperProvider) ois.readObject(); recordUnmapperProvider = (RecordUnmapperProvider) ois.readObject(); diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java index 918347e1db..584691148a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java @@ -65,6 +65,7 @@ import java.io.Serializable; import java.io.StringReader; import java.math.BigInteger; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; @@ -305,7 +306,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri } public DefaultDSLContext(SQLDialect dialect, Settings settings) { - this(new DefaultConfiguration(new NoConnectionProvider(), null, null, null, null, null, null, null, null, null, null, null, dialect, settings, null)); + this(new DefaultConfiguration(new NoConnectionProvider(), null, null, null, null, null, null, null, null, null, null, null, null, dialect, settings, null)); } public DefaultDSLContext(Connection connection, SQLDialect dialect) { @@ -313,7 +314,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri } public DefaultDSLContext(Connection connection, SQLDialect dialect, Settings settings) { - this(new DefaultConfiguration(new DefaultConnectionProvider(connection), null, null, null, null, null, null, null, null, null, null, null, dialect, settings, null)); + this(new DefaultConfiguration(new DefaultConnectionProvider(connection), null, null, null, null, null, null, null, null, null, null, null, null, dialect, settings, null)); } public DefaultDSLContext(DataSource datasource, SQLDialect dialect) { @@ -321,7 +322,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri } public DefaultDSLContext(DataSource datasource, SQLDialect dialect, Settings settings) { - this(new DefaultConfiguration(new DataSourceConnectionProvider(datasource), null, null, null, null, null, null, null, null, null, null, null, dialect, settings, null)); + this(new DefaultConfiguration(new DataSourceConnectionProvider(datasource), null, null, null, null, null, null, null, null, null, null, null, null, dialect, settings, null)); } public DefaultDSLContext(ConnectionProvider connectionProvider, SQLDialect dialect) { @@ -329,7 +330,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri } public DefaultDSLContext(ConnectionProvider connectionProvider, SQLDialect dialect, Settings settings) { - this(new DefaultConfiguration(connectionProvider, null, null, null, null, null, null, null, null, null, null, null, dialect, settings, null)); + this(new DefaultConfiguration(connectionProvider, null, null, null, null, null, null, null, null, null, null, null, null, dialect, settings, null)); } public DefaultDSLContext(Configuration configuration) { @@ -399,7 +400,27 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri @Override public Meta meta() { - return new MetaImpl(configuration()); + return configuration().metaProvider().provide(); + } + + @Override + public Meta meta(DatabaseMetaData meta) { + return new MetaImpl(configuration(), meta); + } + + @Override + public Meta meta(Catalog... catalogs) { + return null; + } + + @Override + public Meta meta(Schema... schemas) { + return null; + } + + @Override + public Meta meta(Table... tables) { + return null; } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultMetaProvider.java b/jOOQ/src/main/java/org/jooq/impl/DefaultMetaProvider.java new file mode 100644 index 0000000000..3d852d0c7e --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultMetaProvider.java @@ -0,0 +1,64 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: http://www.jooq.org/licenses + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ +package org.jooq.impl; + +import java.sql.DatabaseMetaData; + +import org.jooq.Configuration; +import org.jooq.Meta; +import org.jooq.MetaProvider; + +/** + * A default implementation of the {@link MetaProvider}, which provides meta + * data information based on the JDBC {@link DatabaseMetaData} API. + * + * @author Lukas Eder + */ +public class DefaultMetaProvider implements MetaProvider { + + private final Configuration configuration; + + public DefaultMetaProvider(Configuration configuration) { + this.configuration = configuration; + } + + @Override + public Meta provide() { + return new MetaImpl(configuration, null); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java b/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java index 303349dbbf..a1a66628c2 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MetaImpl.java @@ -119,6 +119,7 @@ import org.jooq.SortField; import org.jooq.Table; import org.jooq.TableField; import org.jooq.UniqueKey; +import org.jooq.exception.DataAccessException; import org.jooq.exception.SQLDialectNotSupportedException; import org.jooq.tools.StringUtils; @@ -142,11 +143,13 @@ final class MetaImpl implements Meta, Serializable { private final DSLContext ctx; private final Configuration configuration; + private final DatabaseMetaData databaseMetaData; private final boolean inverseSchemaCatalog; - MetaImpl(Configuration configuration) { + MetaImpl(Configuration configuration, DatabaseMetaData databaseMetaData) { this.ctx = DSL.using(configuration); this.configuration = configuration; + this.databaseMetaData = databaseMetaData; this.inverseSchemaCatalog = INVERSE_SCHEMA_CATALOG.contains(configuration.family()); } @@ -155,12 +158,20 @@ final class MetaImpl implements Meta, Serializable { } private final Result meta(final MetaFunction consumer) { - return ctx.connectionResult(new ConnectionCallable>() { - @Override - public Result run(Connection connection) throws SQLException { - return consumer.run(connection.getMetaData()); + if (databaseMetaData == null) + return ctx.connectionResult(new ConnectionCallable>() { + @Override + public Result run(Connection connection) throws SQLException { + return consumer.run(connection.getMetaData()); + } + }); + else + try { + return consumer.run(databaseMetaData); + } + catch (SQLException e) { + throw new DataAccessException("Error while running MetaFunction", e); } - }); } @Override diff --git a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java index 384c1484f0..07b3db0ffc 100644 --- a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java +++ b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockConfiguration.java @@ -53,6 +53,7 @@ import org.jooq.DiagnosticsListenerProvider; import org.jooq.ExecuteListener; import org.jooq.ExecuteListenerProvider; import org.jooq.ExecutorProvider; +import org.jooq.MetaProvider; import org.jooq.RecordListener; import org.jooq.RecordListenerProvider; import org.jooq.RecordMapper; @@ -124,6 +125,11 @@ public class MockConfiguration implements Configuration { return new MockConnectionProvider(delegate.connectionProvider(), provider); } + @Override + public MetaProvider metaProvider() { + return delegate.metaProvider(); + } + @Override public ExecutorProvider executorProvider() { return delegate.executorProvider(); @@ -206,6 +212,11 @@ public class MockConfiguration implements Configuration { return delegate.set(newConnectionProvider); } + @Override + public Configuration set(MetaProvider newMetaProvider) { + return delegate.set(newMetaProvider); + } + @Override public Configuration set(Connection newConnection) { return delegate.set(newConnection); @@ -343,6 +354,11 @@ public class MockConfiguration implements Configuration { return delegate.derive(newConnectionProvider); } + @Override + public Configuration derive(MetaProvider newMetaProvider) { + return delegate.derive(newMetaProvider); + } + @Override public Configuration derive(Executor newExecutor) { return delegate.derive(newExecutor);