You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metamodel.apache.org by ka...@apache.org on 2014/05/18 21:40:05 UTC
git commit: METAMODEL-56: Fixed metadata of converted JDBC LOBs.
Repository: incubator-metamodel
Updated Branches:
refs/heads/master 7c21e0652 -> bd54b1e0d
METAMODEL-56: Fixed metadata of converted JDBC LOBs.
Project: http://git-wip-us.apache.org/repos/asf/incubator-metamodel/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-metamodel/commit/bd54b1e0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-metamodel/tree/bd54b1e0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-metamodel/diff/bd54b1e0
Branch: refs/heads/master
Commit: bd54b1e0d04b697f3d8c882ddafb66de9562c14d
Parents: 7c21e06
Author: Kasper Sørensen <i....@gmail.com>
Authored: Sun May 18 21:39:13 2014 +0200
Committer: Kasper Sørensen <i....@gmail.com>
Committed: Sun May 18 21:39:13 2014 +0200
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../apache/metamodel/jdbc/JdbcDataContext.java | 12 +-
.../org/apache/metamodel/jdbc/JdbcDataSet.java | 27 +-
.../metamodel/jdbc/JdbcMetadataLoader.java | 770 ++++++++++---------
.../org/apache/metamodel/jdbc/JdbcUtils.java | 3 +
.../metamodel/jdbc/JdbcTestTemplates.java | 67 +-
6 files changed, 452 insertions(+), 428 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/bd54b1e0/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 9c46fad..d32a9d9 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -2,6 +2,7 @@ Apache MetaModel 4.1.0-incubating
* [METAMODEL-13] - Added support for Apache HBase via the new module "MetaModel-hbase"
* [METAMODEL-54] - ColumnType converted from enum to interface to allow for further specialization in modules
+ * [METAMODEL-56] - Made separate column types for converted JDBC LOBs - "CLOB as String" and "BLOB as bytes".
* [METAMODEL-41] - Added a parser for SimpleTableDef objects (SimpleTableDefParser). It parses statements similar to CREATE TABLE statements, although without the "CREATE TABLE" prefix. For example: foo (bar INTEGER, baz VARCHAR)
* [METAMODEL-11] - New module "MetaModel-spring" which adds a convenient FactoryBean to produce various types of DataContext objects based on externalizable parameters, for Spring framework users.
* [METAMODEL-32] - Fixed thread-safety issue in Excel module when tables (sheets) metadata is updated.
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/bd54b1e0/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataContext.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataContext.java b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataContext.java
index 6a4b8a0..a20924c 100644
--- a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataContext.java
+++ b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataContext.java
@@ -51,7 +51,10 @@ import org.apache.metamodel.jdbc.dialects.PostgresqlQueryRewriter;
import org.apache.metamodel.jdbc.dialects.SQLServerQueryRewriter;
import org.apache.metamodel.query.CompiledQuery;
import org.apache.metamodel.query.Query;
+import org.apache.metamodel.schema.ColumnType;
+import org.apache.metamodel.schema.ColumnTypeImpl;
import org.apache.metamodel.schema.Schema;
+import org.apache.metamodel.schema.SuperColumnType;
import org.apache.metamodel.schema.TableType;
import org.apache.metamodel.util.FileHelper;
import org.slf4j.Logger;
@@ -64,7 +67,7 @@ public class JdbcDataContext extends AbstractDataContext implements UpdateableDa
public static final String SYSTEM_PROPERTY_BATCH_UPDATES = "metamodel.jdbc.batch.updates";
public static final String SYSTEM_PROPERTY_CONVERT_LOBS = "metamodel.jdbc.convert.lobs";
-
+
public static final String SYSTEM_PROPERTY_COMPILED_QUERY_POOL_MAX_SIZE = "metamodel.jdbc.compiledquery.pool.max.size";
public static final String SYSTEM_PROPERTY_COMPILED_QUERY_POOL_MIN_EVICTABLE_IDLE_TIME_MILLIS = "metamodel.jdbc.compiledquery.pool.idle.timeout";
public static final String SYSTEM_PROPERTY_COMPILED_QUERY_POOL_TIME_BETWEEN_EVICTION_RUNS_MILLIS = "metamodel.jdbc.compiledquery.pool.eviction.period.millis";
@@ -77,6 +80,11 @@ public class JdbcDataContext extends AbstractDataContext implements UpdateableDa
public static final String DATABASE_PRODUCT_DB2 = "DB2";
public static final String DATABASE_PRODUCT_DB2_PREFIX = "DB2/";
+ public static final ColumnType COLUMN_TYPE_CLOB_AS_STRING = new ColumnTypeImpl("CLOB",
+ SuperColumnType.LITERAL_TYPE, String.class, true);
+ public static final ColumnType COLUMN_TYPE_BLOB_AS_BYTES = new ColumnTypeImpl("BLOB", SuperColumnType.BINARY_TYPE,
+ byte[].class, true);
+
private static final Logger logger = LoggerFactory.getLogger(JdbcDataContext.class);
private final FetchSizeCalculator _fetchSizeCalculator;
@@ -748,7 +756,7 @@ public class JdbcDataContext extends AbstractDataContext implements UpdateableDa
public void executeUpdate(final UpdateScript update) {
final JdbcUpdateCallback updateCallback;
- if (_supportsBatchUpdates && update instanceof BatchUpdateScript) {
+ if (_supportsBatchUpdates && update instanceof BatchUpdateScript) {
updateCallback = new JdbcBatchUpdateCallback(this);
} else {
updateCallback = new JdbcSimpleUpdateCallback(this);
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/bd54b1e0/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataSet.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataSet.java b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataSet.java
index e730b6a..aebe4d4 100644
--- a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataSet.java
+++ b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcDataSet.java
@@ -41,8 +41,6 @@ import org.slf4j.LoggerFactory;
/**
* DataSet implementation that wraps a JDBC resultset.
- *
- * @author Kasper Sørensen
*/
final class JdbcDataSet extends AbstractDataSet {
@@ -163,22 +161,22 @@ final class JdbcDataSet extends AbstractDataSet {
return _resultSet.getTimestamp(columnIndex);
} else if (type == ColumnType.BLOB) {
final Blob blob = _resultSet.getBlob(columnIndex);
- if (isLobConversionEnabled()) {
- final InputStream inputStream = blob.getBinaryStream();
- final byte[] bytes = FileHelper.readAsBytes(inputStream);
- return bytes;
- }
return blob;
+ } else if (type == JdbcDataContext.COLUMN_TYPE_BLOB_AS_BYTES) {
+ final Blob blob = _resultSet.getBlob(columnIndex);
+ final InputStream inputStream = blob.getBinaryStream();
+ final byte[] bytes = FileHelper.readAsBytes(inputStream);
+ return bytes;
} else if (type.isBinary()) {
return _resultSet.getBytes(columnIndex);
} else if (type == ColumnType.CLOB || type == ColumnType.NCLOB) {
final Clob clob = _resultSet.getClob(columnIndex);
- if (isLobConversionEnabled()) {
- final Reader reader = clob.getCharacterStream();
- final String result = FileHelper.readAsString(reader);
- return result;
- }
return clob;
+ } else if (type == JdbcDataContext.COLUMN_TYPE_CLOB_AS_STRING) {
+ final Clob clob = _resultSet.getClob(columnIndex);
+ final Reader reader = clob.getCharacterStream();
+ final String result = FileHelper.readAsString(reader);
+ return result;
} else if (type.isBoolean()) {
return _resultSet.getBoolean(columnIndex);
}
@@ -191,11 +189,6 @@ final class JdbcDataSet extends AbstractDataSet {
return _resultSet.getObject(columnIndex);
}
- private boolean isLobConversionEnabled() {
- final String systemProperty = System.getProperty(JdbcDataContext.SYSTEM_PROPERTY_CONVERT_LOBS);
- return "true".equals(systemProperty);
- }
-
/**
* {@inheritDoc}
*/
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/bd54b1e0/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcMetadataLoader.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcMetadataLoader.java b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcMetadataLoader.java
index 85c2514..54ad378 100644
--- a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcMetadataLoader.java
+++ b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcMetadataLoader.java
@@ -44,384 +44,396 @@ import org.slf4j.LoggerFactory;
*/
final class JdbcMetadataLoader implements MetadataLoader {
- private static final Logger logger = LoggerFactory.getLogger(JdbcMetadataLoader.class);
-
- private final JdbcDataContext _dataContext;
- private final boolean _usesCatalogsAsSchemas;
- private final String _identifierQuoteString;
-
- // these three sets contains the system identifies of whether specific items
- // have been loaded for tables/schemas. Using system identities avoid having
- // to call equals(...) method etc. while doing lazy loading of these items.
- // Invoking equals(...) would be prone to stack overflows ...
- private final Set<Integer> _loadedRelations;
- private final Set<Integer> _loadedColumns;
- private final Set<Integer> _loadedIndexes;
- private final Set<Integer> _loadedPrimaryKeys;
-
- public JdbcMetadataLoader(JdbcDataContext dataContext, boolean usesCatalogsAsSchemas, String identifierQuoteString) {
- _dataContext = dataContext;
- _usesCatalogsAsSchemas = usesCatalogsAsSchemas;
- _identifierQuoteString = identifierQuoteString;
- _loadedRelations = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
- _loadedColumns = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
- _loadedIndexes = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
- _loadedPrimaryKeys = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
- }
-
- @Override
- public void loadTables(JdbcSchema schema) {
- final Connection connection = _dataContext.getConnection();
- try {
- final DatabaseMetaData metaData = connection.getMetaData();
-
- // Creates string array to represent the table types
- final String[] types = JdbcUtils.getTableTypesAsStrings(_dataContext.getTableTypes());
- loadTables(schema, metaData, types);
- } catch (SQLException e) {
- throw JdbcUtils.wrapException(e, "retrieve table metadata for " + schema.getName());
- } finally {
- _dataContext.close(connection, null, null);
- }
- }
-
- private void loadTables(JdbcSchema schema, DatabaseMetaData metaData, String[] types) {
- String catalogName = _dataContext.getCatalogName();
-
- ResultSet rs = null;
- try {
- if (logger.isDebugEnabled()) {
- logger.debug("Querying for table types " + Arrays.toString(types) + " in catalog: " + catalogName
- + ", schema: " + schema.getName());
- }
- if (_usesCatalogsAsSchemas) {
- rs = metaData.getTables(schema.getName(), null, null, types);
- } else {
- rs = metaData.getTables(catalogName, schema.getName(), null, types);
- }
- schema.clearTables();
- int tableNumber = -1;
- while (rs.next()) {
- tableNumber++;
- String tableCatalog = rs.getString(1);
- String tableSchema = rs.getString(2);
- String tableName = rs.getString(3);
- String tableTypeName = rs.getString(4);
- TableType tableType = TableType.getTableType(tableTypeName);
- String tableRemarks = rs.getString(5);
-
- if (logger.isDebugEnabled()) {
- logger.debug("Found table: tableCatalog=" + tableCatalog + ",tableSchema=" + tableSchema
- + ",tableName=" + tableName);
- }
-
- if (tableSchema == null) {
- tableSchema = tableCatalog;
- }
-
- JdbcTable table = new JdbcTable(tableName, tableType, schema, this);
- table.setRemarks(tableRemarks);
- table.setQuote(_identifierQuoteString);
- schema.addTable(table);
- }
-
- final int tablesReturned = tableNumber + 1;
- if (tablesReturned == 0) {
- logger.info("No table metadata records returned for schema '{}'", schema.getName());
- } else {
- logger.debug("Returned {} table metadata records for schema '{}'", new Object[] { tablesReturned,
- schema.getName() });
- }
-
- } catch (SQLException e) {
- throw JdbcUtils.wrapException(e, "retrieve table metadata for " + schema.getName());
- } finally {
- _dataContext.close(null, rs, null);
- }
- }
-
- @Override
- public void loadIndexes(JdbcTable table) {
- final int identity = System.identityHashCode(table);
- if (_loadedIndexes.contains(identity)) {
- return;
- }
- synchronized (this) {
- if (_loadedIndexes.contains(identity)) {
- return;
- }
-
- final Connection connection = _dataContext.getConnection();
- try {
- DatabaseMetaData metaData = connection.getMetaData();
- loadIndexes(table, metaData);
- _loadedIndexes.add(identity);
- } catch (SQLException e) {
- throw JdbcUtils.wrapException(e, "load indexes");
- } finally {
- _dataContext.close(connection, null, null);
- }
- }
- }
-
- @Override
- public void loadPrimaryKeys(JdbcTable table) {
- final int identity = System.identityHashCode(table);
- if (_loadedPrimaryKeys.contains(identity)) {
- return;
- }
- synchronized (this) {
- if (_loadedPrimaryKeys.contains(identity)) {
- return;
- }
- final Connection connection = _dataContext.getConnection();
- try {
- DatabaseMetaData metaData = connection.getMetaData();
- loadPrimaryKeys(table, metaData);
- _loadedPrimaryKeys.add(identity);
- } catch (SQLException e) {
- throw JdbcUtils.wrapException(e, "load primary keys");
- } finally {
- _dataContext.close(connection, null, null);
- }
- }
- }
-
- private void loadPrimaryKeys(JdbcTable table, DatabaseMetaData metaData) throws MetaModelException {
- Schema schema = table.getSchema();
- ResultSet rs = null;
-
- try {
- if (_usesCatalogsAsSchemas) {
- rs = metaData.getPrimaryKeys(schema.getName(), null, table.getName());
- } else {
- rs = metaData.getPrimaryKeys(_dataContext.getCatalogName(), schema.getName(), table.getName());
- }
- while (rs.next()) {
- String columnName = rs.getString(4);
- if (columnName != null) {
- MutableColumn column = (MutableColumn) table.getColumnByName(columnName);
- if (column != null) {
- column.setPrimaryKey(true);
- } else {
- logger.error("Indexed column \"{}\" could not be found in table: {}", columnName, table);
- }
- }
- }
- } catch (SQLException e) {
- throw JdbcUtils.wrapException(e, "retrieve primary keys for " + table.getName());
- } finally {
- _dataContext.close(null, rs, null);
- }
- }
-
- private void loadIndexes(Table table, DatabaseMetaData metaData) throws MetaModelException {
- Schema schema = table.getSchema();
- ResultSet rs = null;
- // Ticket #170: IndexInfo is nice-to-have, not need-to-have, so
- // we will do a nice failover on SQLExceptions
- try {
- if (_usesCatalogsAsSchemas) {
- rs = metaData.getIndexInfo(schema.getName(), null, table.getName(), false, true);
- } else {
- rs = metaData.getIndexInfo(_dataContext.getCatalogName(), schema.getName(), table.getName(), false,
- true);
- }
- while (rs.next()) {
- String columnName = rs.getString(9);
- if (columnName != null) {
- MutableColumn column = (MutableColumn) table.getColumnByName(columnName);
- if (column != null) {
- column.setIndexed(true);
- } else {
- logger.error("Indexed column \"{}\" could not be found in table: {}", columnName, table);
- }
- }
- }
- } catch (SQLException e) {
- throw JdbcUtils.wrapException(e, "retrieve index information for " + table.getName());
- } finally {
- _dataContext.close(null, rs, null);
- }
- }
-
- /**
- * Loads column metadata (no indexes though) for a table
- *
- * @param table
- */
- @Override
- public void loadColumns(JdbcTable table) {
- final int identity = System.identityHashCode(table);
- if (_loadedColumns.contains(identity)) {
- return;
- }
- synchronized (this) {
- if (_loadedColumns.contains(identity)) {
- return;
- }
-
- final Connection connection = _dataContext.getConnection();
- try {
- DatabaseMetaData metaData = connection.getMetaData();
- loadColumns(table, metaData);
- _loadedColumns.add(identity);
- } catch (Exception e) {
- logger.error("Could not load columns for table: " + table, e);
- } finally {
- _dataContext.close(connection, null, null);
- }
- }
- }
-
- private void loadColumns(JdbcTable table, DatabaseMetaData metaData) {
- final Schema schema = table.getSchema();
- ResultSet rs = null;
- try {
- if (logger.isDebugEnabled()) {
- logger.debug("Querying for columns in table: " + table.getName());
- }
- int columnNumber = -1;
- if (_usesCatalogsAsSchemas) {
- rs = metaData.getColumns(schema.getName(), null, table.getName(), null);
- } else {
- rs = metaData.getColumns(_dataContext.getCatalogName(), schema.getName(), table.getName(), null);
- }
- while (rs.next()) {
- columnNumber++;
- final String columnName = rs.getString(4);
- if (_identifierQuoteString == null && new StringTokenizer(columnName).countTokens() > 1) {
- logger.warn("column name contains whitespace: \"" + columnName + "\".");
- }
-
- final int jdbcType = rs.getInt(5);
- final String nativeType = rs.getString(6);
- final Integer columnSize = rs.getInt(7);
-
- if (logger.isDebugEnabled()) {
- logger.debug("Found column: table=" + table.getName() + ",columnName=" + columnName
- + ",nativeType=" + nativeType + ",columnSize=" + columnSize);
- }
-
- final ColumnType columnType = _dataContext.getQueryRewriter().getColumnType(jdbcType, nativeType,
- columnSize);
-
- final int jdbcNullable = rs.getInt(11);
- final Boolean nullable;
- if (jdbcNullable == DatabaseMetaData.columnNullable) {
- nullable = true;
- } else if (jdbcNullable == DatabaseMetaData.columnNoNulls) {
- nullable = false;
- } else {
- nullable = null;
- }
-
- final String remarks = rs.getString(12);
-
- final JdbcColumn column = new JdbcColumn(columnName, columnType, table, columnNumber, nullable);
- column.setRemarks(remarks);
- column.setNativeType(nativeType);
- column.setColumnSize(columnSize);
- column.setQuote(_identifierQuoteString);
- table.addColumn(column);
- }
-
- final int columnsReturned = columnNumber + 1;
- if (columnsReturned == 0) {
- logger.info("No column metadata records returned for table '{}' in schema '{}'", table.getName(),
- schema.getName());
- } else {
- logger.debug("Returned {} column metadata records for table '{}' in schema '{}'", new Object[] {
- columnsReturned, table.getName(), schema.getName() });
- }
-
- } catch (SQLException e) {
- throw JdbcUtils.wrapException(e, "retrieve table metadata for " + table.getName());
- } finally {
- _dataContext.close(null, rs, null);
- }
- }
-
- @Override
- public void loadRelations(JdbcSchema schema) {
- final int identity = System.identityHashCode(schema);
- if (_loadedRelations.contains(identity)) {
- return;
- }
- synchronized (this) {
- if (_loadedRelations.contains(identity)) {
- return;
- }
- final Connection connection = _dataContext.getConnection();
- try {
- final Table[] tables = schema.getTables();
- final DatabaseMetaData metaData = connection.getMetaData();
- for (Table table : tables) {
- loadRelations(table, metaData);
- }
- _loadedRelations.add(identity);
- } catch (Exception e) {
- logger.error("Could not load relations for schema: " + schema, e);
- } finally {
- _dataContext.close(connection, null, null);
- }
- }
- }
-
- private void loadRelations(Table table, DatabaseMetaData metaData) {
- Schema schema = table.getSchema();
- ResultSet rs = null;
- try {
- if (_usesCatalogsAsSchemas) {
- rs = metaData.getImportedKeys(schema.getName(), null, table.getName());
- } else {
- rs = metaData.getImportedKeys(_dataContext.getCatalogName(), schema.getName(), table.getName());
- }
- loadRelations(rs, schema);
- } catch (SQLException e) {
- throw JdbcUtils.wrapException(e, "retrieve imported keys for " + table.getName());
- } finally {
- _dataContext.close(null, rs, null);
- }
- }
-
- private void loadRelations(ResultSet rs, Schema schema) throws SQLException {
- while (rs.next()) {
- String pkTableName = rs.getString(3);
- String pkColumnName = rs.getString(4);
-
- Column pkColumn = null;
- Table pkTable = schema.getTableByName(pkTableName);
- if (pkTable != null) {
- pkColumn = pkTable.getColumnByName(pkColumnName);
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Found primary key relation: tableName=" + pkTableName + ",columnName=" + pkColumnName
- + ", matching column: " + pkColumn);
- }
-
- String fkTableName = rs.getString(7);
- String fkColumnName = rs.getString(8);
- Column fkColumn = null;
- Table fkTable = schema.getTableByName(fkTableName);
- if (fkTable != null) {
- fkColumn = fkTable.getColumnByName(fkColumnName);
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Found foreign key relation: tableName=" + fkTableName + ",columnName=" + fkColumnName
- + ", matching column: " + fkColumn);
- }
-
- if (pkColumn == null || fkColumn == null) {
- logger.error(
- "Could not find relation columns: pkTableName={},pkColumnName={},fkTableName={},fkColumnName={}",
- new Object[] { pkTableName, pkColumnName, fkTableName, fkColumnName });
- logger.error("pkColumn={}", pkColumn);
- logger.error("fkColumn={}", fkColumn);
- } else {
- MutableRelationship.createRelationship(new Column[] { pkColumn }, new Column[] { fkColumn });
- }
- }
- }
+ private static final Logger logger = LoggerFactory.getLogger(JdbcMetadataLoader.class);
+
+ private final JdbcDataContext _dataContext;
+ private final boolean _usesCatalogsAsSchemas;
+ private final String _identifierQuoteString;
+
+ // these three sets contains the system identifies of whether specific items
+ // have been loaded for tables/schemas. Using system identities avoid having
+ // to call equals(...) method etc. while doing lazy loading of these items.
+ // Invoking equals(...) would be prone to stack overflows ...
+ private final Set<Integer> _loadedRelations;
+ private final Set<Integer> _loadedColumns;
+ private final Set<Integer> _loadedIndexes;
+ private final Set<Integer> _loadedPrimaryKeys;
+
+ public JdbcMetadataLoader(JdbcDataContext dataContext, boolean usesCatalogsAsSchemas, String identifierQuoteString) {
+ _dataContext = dataContext;
+ _usesCatalogsAsSchemas = usesCatalogsAsSchemas;
+ _identifierQuoteString = identifierQuoteString;
+ _loadedRelations = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
+ _loadedColumns = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
+ _loadedIndexes = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
+ _loadedPrimaryKeys = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());
+ }
+
+ @Override
+ public void loadTables(JdbcSchema schema) {
+ final Connection connection = _dataContext.getConnection();
+ try {
+ final DatabaseMetaData metaData = connection.getMetaData();
+
+ // Creates string array to represent the table types
+ final String[] types = JdbcUtils.getTableTypesAsStrings(_dataContext.getTableTypes());
+ loadTables(schema, metaData, types);
+ } catch (SQLException e) {
+ throw JdbcUtils.wrapException(e, "retrieve table metadata for " + schema.getName());
+ } finally {
+ _dataContext.close(connection, null, null);
+ }
+ }
+
+ private void loadTables(JdbcSchema schema, DatabaseMetaData metaData, String[] types) {
+ String catalogName = _dataContext.getCatalogName();
+
+ ResultSet rs = null;
+ try {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Querying for table types " + Arrays.toString(types) + " in catalog: " + catalogName
+ + ", schema: " + schema.getName());
+ }
+ if (_usesCatalogsAsSchemas) {
+ rs = metaData.getTables(schema.getName(), null, null, types);
+ } else {
+ rs = metaData.getTables(catalogName, schema.getName(), null, types);
+ }
+ schema.clearTables();
+ int tableNumber = -1;
+ while (rs.next()) {
+ tableNumber++;
+ String tableCatalog = rs.getString(1);
+ String tableSchema = rs.getString(2);
+ String tableName = rs.getString(3);
+ String tableTypeName = rs.getString(4);
+ TableType tableType = TableType.getTableType(tableTypeName);
+ String tableRemarks = rs.getString(5);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found table: tableCatalog=" + tableCatalog + ",tableSchema=" + tableSchema
+ + ",tableName=" + tableName);
+ }
+
+ if (tableSchema == null) {
+ tableSchema = tableCatalog;
+ }
+
+ JdbcTable table = new JdbcTable(tableName, tableType, schema, this);
+ table.setRemarks(tableRemarks);
+ table.setQuote(_identifierQuoteString);
+ schema.addTable(table);
+ }
+
+ final int tablesReturned = tableNumber + 1;
+ if (tablesReturned == 0) {
+ logger.info("No table metadata records returned for schema '{}'", schema.getName());
+ } else {
+ logger.debug("Returned {} table metadata records for schema '{}'", new Object[] { tablesReturned,
+ schema.getName() });
+ }
+
+ } catch (SQLException e) {
+ throw JdbcUtils.wrapException(e, "retrieve table metadata for " + schema.getName());
+ } finally {
+ _dataContext.close(null, rs, null);
+ }
+ }
+
+ @Override
+ public void loadIndexes(JdbcTable table) {
+ final int identity = System.identityHashCode(table);
+ if (_loadedIndexes.contains(identity)) {
+ return;
+ }
+ synchronized (this) {
+ if (_loadedIndexes.contains(identity)) {
+ return;
+ }
+
+ final Connection connection = _dataContext.getConnection();
+ try {
+ DatabaseMetaData metaData = connection.getMetaData();
+ loadIndexes(table, metaData);
+ _loadedIndexes.add(identity);
+ } catch (SQLException e) {
+ throw JdbcUtils.wrapException(e, "load indexes");
+ } finally {
+ _dataContext.close(connection, null, null);
+ }
+ }
+ }
+
+ @Override
+ public void loadPrimaryKeys(JdbcTable table) {
+ final int identity = System.identityHashCode(table);
+ if (_loadedPrimaryKeys.contains(identity)) {
+ return;
+ }
+ synchronized (this) {
+ if (_loadedPrimaryKeys.contains(identity)) {
+ return;
+ }
+ final Connection connection = _dataContext.getConnection();
+ try {
+ DatabaseMetaData metaData = connection.getMetaData();
+ loadPrimaryKeys(table, metaData);
+ _loadedPrimaryKeys.add(identity);
+ } catch (SQLException e) {
+ throw JdbcUtils.wrapException(e, "load primary keys");
+ } finally {
+ _dataContext.close(connection, null, null);
+ }
+ }
+ }
+
+ private void loadPrimaryKeys(JdbcTable table, DatabaseMetaData metaData) throws MetaModelException {
+ Schema schema = table.getSchema();
+ ResultSet rs = null;
+
+ try {
+ if (_usesCatalogsAsSchemas) {
+ rs = metaData.getPrimaryKeys(schema.getName(), null, table.getName());
+ } else {
+ rs = metaData.getPrimaryKeys(_dataContext.getCatalogName(), schema.getName(), table.getName());
+ }
+ while (rs.next()) {
+ String columnName = rs.getString(4);
+ if (columnName != null) {
+ MutableColumn column = (MutableColumn) table.getColumnByName(columnName);
+ if (column != null) {
+ column.setPrimaryKey(true);
+ } else {
+ logger.error("Indexed column \"{}\" could not be found in table: {}", columnName, table);
+ }
+ }
+ }
+ } catch (SQLException e) {
+ throw JdbcUtils.wrapException(e, "retrieve primary keys for " + table.getName());
+ } finally {
+ _dataContext.close(null, rs, null);
+ }
+ }
+
+ private void loadIndexes(Table table, DatabaseMetaData metaData) throws MetaModelException {
+ Schema schema = table.getSchema();
+ ResultSet rs = null;
+ // Ticket #170: IndexInfo is nice-to-have, not need-to-have, so
+ // we will do a nice failover on SQLExceptions
+ try {
+ if (_usesCatalogsAsSchemas) {
+ rs = metaData.getIndexInfo(schema.getName(), null, table.getName(), false, true);
+ } else {
+ rs = metaData.getIndexInfo(_dataContext.getCatalogName(), schema.getName(), table.getName(), false,
+ true);
+ }
+ while (rs.next()) {
+ String columnName = rs.getString(9);
+ if (columnName != null) {
+ MutableColumn column = (MutableColumn) table.getColumnByName(columnName);
+ if (column != null) {
+ column.setIndexed(true);
+ } else {
+ logger.error("Indexed column \"{}\" could not be found in table: {}", columnName, table);
+ }
+ }
+ }
+ } catch (SQLException e) {
+ throw JdbcUtils.wrapException(e, "retrieve index information for " + table.getName());
+ } finally {
+ _dataContext.close(null, rs, null);
+ }
+ }
+
+ /**
+ * Loads column metadata (no indexes though) for a table
+ *
+ * @param table
+ */
+ @Override
+ public void loadColumns(JdbcTable table) {
+ final int identity = System.identityHashCode(table);
+ if (_loadedColumns.contains(identity)) {
+ return;
+ }
+ synchronized (this) {
+ if (_loadedColumns.contains(identity)) {
+ return;
+ }
+
+ final Connection connection = _dataContext.getConnection();
+ try {
+ DatabaseMetaData metaData = connection.getMetaData();
+ loadColumns(table, metaData);
+ _loadedColumns.add(identity);
+ } catch (Exception e) {
+ logger.error("Could not load columns for table: " + table, e);
+ } finally {
+ _dataContext.close(connection, null, null);
+ }
+ }
+ }
+
+ private boolean isLobConversionEnabled() {
+ final String systemProperty = System.getProperty(JdbcDataContext.SYSTEM_PROPERTY_CONVERT_LOBS);
+ return "true".equals(systemProperty);
+ }
+
+ private void loadColumns(JdbcTable table, DatabaseMetaData metaData) {
+ final boolean convertLobs = isLobConversionEnabled();
+ final Schema schema = table.getSchema();
+ ResultSet rs = null;
+ try {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Querying for columns in table: " + table.getName());
+ }
+ int columnNumber = -1;
+ if (_usesCatalogsAsSchemas) {
+ rs = metaData.getColumns(schema.getName(), null, table.getName(), null);
+ } else {
+ rs = metaData.getColumns(_dataContext.getCatalogName(), schema.getName(), table.getName(), null);
+ }
+ while (rs.next()) {
+ columnNumber++;
+ final String columnName = rs.getString(4);
+ if (_identifierQuoteString == null && new StringTokenizer(columnName).countTokens() > 1) {
+ logger.warn("column name contains whitespace: \"" + columnName + "\".");
+ }
+
+ final int jdbcType = rs.getInt(5);
+ final String nativeType = rs.getString(6);
+ final Integer columnSize = rs.getInt(7);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found column: table=" + table.getName() + ",columnName=" + columnName
+ + ",nativeType=" + nativeType + ",columnSize=" + columnSize);
+ }
+
+ ColumnType columnType = _dataContext.getQueryRewriter().getColumnType(jdbcType, nativeType, columnSize);
+ if (convertLobs) {
+ if (columnType == ColumnType.CLOB || columnType == ColumnType.NCLOB) {
+ columnType = JdbcDataContext.COLUMN_TYPE_CLOB_AS_STRING;
+ } else if (columnType == ColumnType.BLOB) {
+ columnType = JdbcDataContext.COLUMN_TYPE_BLOB_AS_BYTES;
+ }
+ }
+
+ final int jdbcNullable = rs.getInt(11);
+ final Boolean nullable;
+ if (jdbcNullable == DatabaseMetaData.columnNullable) {
+ nullable = true;
+ } else if (jdbcNullable == DatabaseMetaData.columnNoNulls) {
+ nullable = false;
+ } else {
+ nullable = null;
+ }
+
+ final String remarks = rs.getString(12);
+
+ final JdbcColumn column = new JdbcColumn(columnName, columnType, table, columnNumber, nullable);
+ column.setRemarks(remarks);
+ column.setNativeType(nativeType);
+ column.setColumnSize(columnSize);
+ column.setQuote(_identifierQuoteString);
+ table.addColumn(column);
+ }
+
+ final int columnsReturned = columnNumber + 1;
+ if (columnsReturned == 0) {
+ logger.info("No column metadata records returned for table '{}' in schema '{}'", table.getName(),
+ schema.getName());
+ } else {
+ logger.debug("Returned {} column metadata records for table '{}' in schema '{}'", new Object[] {
+ columnsReturned, table.getName(), schema.getName() });
+ }
+
+ } catch (SQLException e) {
+ throw JdbcUtils.wrapException(e, "retrieve table metadata for " + table.getName());
+ } finally {
+ _dataContext.close(null, rs, null);
+ }
+ }
+
+ @Override
+ public void loadRelations(JdbcSchema schema) {
+ final int identity = System.identityHashCode(schema);
+ if (_loadedRelations.contains(identity)) {
+ return;
+ }
+ synchronized (this) {
+ if (_loadedRelations.contains(identity)) {
+ return;
+ }
+ final Connection connection = _dataContext.getConnection();
+ try {
+ final Table[] tables = schema.getTables();
+ final DatabaseMetaData metaData = connection.getMetaData();
+ for (Table table : tables) {
+ loadRelations(table, metaData);
+ }
+ _loadedRelations.add(identity);
+ } catch (Exception e) {
+ logger.error("Could not load relations for schema: " + schema, e);
+ } finally {
+ _dataContext.close(connection, null, null);
+ }
+ }
+ }
+
+ private void loadRelations(Table table, DatabaseMetaData metaData) {
+ Schema schema = table.getSchema();
+ ResultSet rs = null;
+ try {
+ if (_usesCatalogsAsSchemas) {
+ rs = metaData.getImportedKeys(schema.getName(), null, table.getName());
+ } else {
+ rs = metaData.getImportedKeys(_dataContext.getCatalogName(), schema.getName(), table.getName());
+ }
+ loadRelations(rs, schema);
+ } catch (SQLException e) {
+ throw JdbcUtils.wrapException(e, "retrieve imported keys for " + table.getName());
+ } finally {
+ _dataContext.close(null, rs, null);
+ }
+ }
+
+ private void loadRelations(ResultSet rs, Schema schema) throws SQLException {
+ while (rs.next()) {
+ String pkTableName = rs.getString(3);
+ String pkColumnName = rs.getString(4);
+
+ Column pkColumn = null;
+ Table pkTable = schema.getTableByName(pkTableName);
+ if (pkTable != null) {
+ pkColumn = pkTable.getColumnByName(pkColumnName);
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found primary key relation: tableName=" + pkTableName + ",columnName=" + pkColumnName
+ + ", matching column: " + pkColumn);
+ }
+
+ String fkTableName = rs.getString(7);
+ String fkColumnName = rs.getString(8);
+ Column fkColumn = null;
+ Table fkTable = schema.getTableByName(fkTableName);
+ if (fkTable != null) {
+ fkColumn = fkTable.getColumnByName(fkColumnName);
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug("Found foreign key relation: tableName=" + fkTableName + ",columnName=" + fkColumnName
+ + ", matching column: " + fkColumn);
+ }
+
+ if (pkColumn == null || fkColumn == null) {
+ logger.error(
+ "Could not find relation columns: pkTableName={},pkColumnName={},fkTableName={},fkColumnName={}",
+ new Object[] { pkTableName, pkColumnName, fkTableName, fkColumnName });
+ logger.error("pkColumn={}", pkColumn);
+ logger.error("fkColumn={}", fkColumn);
+ } else {
+ MutableRelationship.createRelationship(new Column[] { pkColumn }, new Column[] { fkColumn });
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/bd54b1e0/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java
----------------------------------------------------------------------
diff --git a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java
index 87e584f..4969bae 100644
--- a/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java
+++ b/jdbc/src/main/java/org/apache/metamodel/jdbc/JdbcUtils.java
@@ -42,6 +42,9 @@ import org.apache.metamodel.util.FormatHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+/**
+ * Various internal utility methods for the JDBC module of MetaModel.
+ */
public final class JdbcUtils {
private static final Logger logger = LoggerFactory
http://git-wip-us.apache.org/repos/asf/incubator-metamodel/blob/bd54b1e0/jdbc/src/test/java/org/apache/metamodel/jdbc/JdbcTestTemplates.java
----------------------------------------------------------------------
diff --git a/jdbc/src/test/java/org/apache/metamodel/jdbc/JdbcTestTemplates.java b/jdbc/src/test/java/org/apache/metamodel/jdbc/JdbcTestTemplates.java
index 8fc878c..0e24d21 100644
--- a/jdbc/src/test/java/org/apache/metamodel/jdbc/JdbcTestTemplates.java
+++ b/jdbc/src/test/java/org/apache/metamodel/jdbc/JdbcTestTemplates.java
@@ -187,7 +187,8 @@ public class JdbcTestTemplates {
assertFalse(ds.next());
// regular IN (with string)
- ds = dc.query().from(schema.getTableByName("test_table")).selectCount().where("code").in("C01", "C02").execute();
+ ds = dc.query().from(schema.getTableByName("test_table")).selectCount().where("code").in("C01", "C02")
+ .execute();
assertTrue(ds.next());
assertEquals("2", ds.getRow().getValue(0).toString());
assertFalse(ds.next());
@@ -200,8 +201,8 @@ public class JdbcTestTemplates {
// irregular IN (with null value) - (currently uses SQL's standard way
// of understanding NULL - see ticket #1058)
- Query query = dc.query().from(schema.getTableByName("test_table")).selectCount().where("code").in("foobar", null, "baz")
- .toQuery();
+ Query query = dc.query().from(schema.getTableByName("test_table")).selectCount().where("code")
+ .in("foobar", null, "baz").toQuery();
String sql = dc.getQueryRewriter().rewriteQuery(query);
assertTrue(sql, sql.endsWith(" IN ('foobar' , 'baz')"));
@@ -272,12 +273,12 @@ public class JdbcTestTemplates {
@Override
public void run(UpdateCallback cb) {
Table table = cb.createTable(schema, "test_table").withColumn("id").ofType(ColumnType.INTEGER)
- .withColumn("birthdate1").ofType(ColumnType.DATE).withColumn("birthdate2").ofType(ColumnType.TIMESTAMP)
- .execute();
+ .withColumn("birthdate1").ofType(ColumnType.DATE).withColumn("birthdate2")
+ .ofType(ColumnType.TIMESTAMP).execute();
cb.insertInto(table).value("id", "1").value("birthdate1", null).execute();
- cb.insertInto(table).value("id", 2).value("birthdate1", "2011-12-21").value("birthdate2", "2011-12-21 14:00:00")
- .execute();
+ cb.insertInto(table).value("id", 2).value("birthdate1", "2011-12-21")
+ .value("birthdate2", "2011-12-21 14:00:00").execute();
}
});
@@ -302,8 +303,8 @@ public class JdbcTestTemplates {
assertFalse(ds.next());
ds.close();
- ds = dc.query().from("test_table").select("id").where("birthdate2").greaterThan(DateUtils.get(2011, Month.DECEMBER, 20))
- .execute();
+ ds = dc.query().from("test_table").select("id").where("birthdate2")
+ .greaterThan(DateUtils.get(2011, Month.DECEMBER, 20)).execute();
assertTrue(ds.next());
assertEquals("Row[values=[2]]", ds.getRow().toString());
assertFalse(ds.next());
@@ -330,8 +331,8 @@ public class JdbcTestTemplates {
});
}
- public static void createInsertAndUpdateDateTypes(final JdbcDataContext dc, final Schema schema, final String tableName)
- throws Exception {
+ public static void createInsertAndUpdateDateTypes(final JdbcDataContext dc, final Schema schema,
+ final String tableName) throws Exception {
if (schema.getTableByName(tableName) != null) {
dc.executeUpdate(new UpdateScript() {
@Override
@@ -344,8 +345,9 @@ public class JdbcTestTemplates {
dc.executeUpdate(new BatchUpdateScript() {
@Override
public void run(UpdateCallback cb) {
- Table table = cb.createTable(schema, tableName).withColumn("id").asPrimaryKey().ofType(ColumnType.INTEGER)
- .withColumn("birthdate").ofType(ColumnType.DATE).withColumn("wakemeup").ofType(ColumnType.TIME).execute();
+ Table table = cb.createTable(schema, tableName).withColumn("id").asPrimaryKey()
+ .ofType(ColumnType.INTEGER).withColumn("birthdate").ofType(ColumnType.DATE)
+ .withColumn("wakemeup").ofType(ColumnType.TIME).execute();
// insert record 1
{
@@ -381,22 +383,25 @@ public class JdbcTestTemplates {
}
});
- DataSet ds = dc.query().from(schema.getTableByName(tableName)).select("id", "birthdate", "wakemeup").orderBy("id")
- .execute();
+ DataSet ds = dc.query().from(schema.getTableByName(tableName)).select("id", "birthdate", "wakemeup")
+ .orderBy("id").execute();
assertTrue(ds.next());
assertEquals("1", ds.getRow().getValue(0).toString());
assertEquals("1982-04-20", ds.getRow().getValue(1).toString());
- assertTrue("Actual value was: " + ds.getRow().getValue(2), ds.getRow().getValue(2).toString().startsWith("07:55:00"));
+ assertTrue("Actual value was: " + ds.getRow().getValue(2),
+ ds.getRow().getValue(2).toString().startsWith("07:55:00"));
assertTrue(ds.next());
assertEquals("2", ds.getRow().getValue(0).toString());
assertEquals("1982-04-21", ds.getRow().getValue(1).toString());
- assertTrue("Actual value was: " + ds.getRow().getValue(2), ds.getRow().getValue(2).toString().startsWith("18:35:00"));
+ assertTrue("Actual value was: " + ds.getRow().getValue(2),
+ ds.getRow().getValue(2).toString().startsWith("18:35:00"));
assertTrue(ds.next());
assertEquals("3", ds.getRow().getValue(0).toString());
assertEquals("2011-12-21", ds.getRow().getValue(1).toString());
- assertTrue("Actual value was: " + ds.getRow().getValue(2), ds.getRow().getValue(2).toString().startsWith("12:00"));
+ assertTrue("Actual value was: " + ds.getRow().getValue(2),
+ ds.getRow().getValue(2).toString().startsWith("12:00"));
assertFalse(ds.next());
ds.close();
@@ -413,27 +418,31 @@ public class JdbcTestTemplates {
cal.set(Calendar.MINUTE, 00);
Date wakeUpTime = cal.getTime();
- callback.update(schema.getTableByName(tableName)).value("birthdate", DateUtils.get(1982, Month.APRIL, 21))
- .value("wakemeup", wakeUpTime).where("birthdate").isEquals(DateUtils.get(1982, Month.APRIL, 20))
- .execute();
+ callback.update(schema.getTableByName(tableName))
+ .value("birthdate", DateUtils.get(1982, Month.APRIL, 21)).value("wakemeup", wakeUpTime)
+ .where("birthdate").isEquals(DateUtils.get(1982, Month.APRIL, 20)).execute();
}
});
- ds = dc.query().from(schema.getTableByName(tableName)).select("id", "birthdate", "wakemeup").orderBy("id").execute();
+ ds = dc.query().from(schema.getTableByName(tableName)).select("id", "birthdate", "wakemeup").orderBy("id")
+ .execute();
assertTrue(ds.next());
assertEquals("1", ds.getRow().getValue(0).toString());
assertEquals("1982-04-21", ds.getRow().getValue(1).toString());
- assertTrue("Actual value was: " + ds.getRow().getValue(2), ds.getRow().getValue(2).toString().startsWith("08:00:00"));
+ assertTrue("Actual value was: " + ds.getRow().getValue(2),
+ ds.getRow().getValue(2).toString().startsWith("08:00:00"));
assertTrue(ds.next());
assertEquals("2", ds.getRow().getValue(0).toString());
assertEquals("1982-04-21", ds.getRow().getValue(1).toString());
- assertTrue("Actual value was: " + ds.getRow().getValue(2), ds.getRow().getValue(2).toString().startsWith("18:35:00"));
+ assertTrue("Actual value was: " + ds.getRow().getValue(2),
+ ds.getRow().getValue(2).toString().startsWith("18:35:00"));
assertTrue(ds.next());
assertEquals("3", ds.getRow().getValue(0).toString());
assertEquals("2011-12-21", ds.getRow().getValue(1).toString());
- assertTrue("Actual value was: " + ds.getRow().getValue(2), ds.getRow().getValue(2).toString().startsWith("12:00"));
+ assertTrue("Actual value was: " + ds.getRow().getValue(2),
+ ds.getRow().getValue(2).toString().startsWith("12:00"));
assertFalse(ds.next());
ds.close();
@@ -449,15 +458,15 @@ public class JdbcTestTemplates {
}
public static void convertClobToString(JdbcDataContext dc) {
- System.setProperty(JdbcDataContext.SYSTEM_PROPERTY_CONVERT_LOBS, "");
+ System.setProperty(JdbcDataContext.SYSTEM_PROPERTY_CONVERT_LOBS, "true");
final Schema schema = dc.getDefaultSchema();
dc.executeUpdate(new UpdateScript() {
@Override
public void run(UpdateCallback callback) {
- Table table = callback.createTable(schema, "clob_test_table").withColumn("id").ofType(ColumnType.INTEGER)
- .asPrimaryKey().withColumn("foo").ofType(ColumnType.CLOB).execute();
+ Table table = callback.createTable(schema, "clob_test_table").withColumn("id")
+ .ofType(ColumnType.INTEGER).asPrimaryKey().withColumn("foo").ofType(ColumnType.CLOB).execute();
callback.insertInto(table).value("id", 1).value("foo", "baaaaz").execute();
@@ -485,8 +494,6 @@ public class JdbcTestTemplates {
assertFalse(ds.next());
ds.close();
- System.setProperty(JdbcDataContext.SYSTEM_PROPERTY_CONVERT_LOBS, "true");
-
ds = dc.query().from(schema, "clob_test_table").select("id", "foo").orderBy("id").execute();
assertTrue(ds.next());
assertEquals("Row[values=[1, baaaaz]]", ds.getRow().toString());