
org.eobjects.metamodel.jdbc.JdbcDataContext Maven / Gradle / Ivy
/**
* eobjects.org MetaModel
* Copyright (C) 2010 eobjects.org
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.eobjects.metamodel.jdbc;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import javax.sql.DataSource;
import org.eobjects.metamodel.AbstractDataContext;
import org.eobjects.metamodel.MetaModelException;
import org.eobjects.metamodel.UpdateScript;
import org.eobjects.metamodel.UpdateableDataContext;
import org.eobjects.metamodel.data.DataSet;
import org.eobjects.metamodel.data.FirstRowDataSet;
import org.eobjects.metamodel.data.MaxRowsDataSet;
import org.eobjects.metamodel.jdbc.dialects.DB2QueryRewriter;
import org.eobjects.metamodel.jdbc.dialects.DefaultQueryRewriter;
import org.eobjects.metamodel.jdbc.dialects.HsqldbQueryRewriter;
import org.eobjects.metamodel.jdbc.dialects.IQueryRewriter;
import org.eobjects.metamodel.jdbc.dialects.MysqlQueryRewriter;
import org.eobjects.metamodel.jdbc.dialects.PostgresqlQueryRewriter;
import org.eobjects.metamodel.jdbc.dialects.SQLServerQueryRewriter;
import org.eobjects.metamodel.query.Query;
import org.eobjects.metamodel.schema.Column;
import org.eobjects.metamodel.schema.ColumnType;
import org.eobjects.metamodel.schema.MutableColumn;
import org.eobjects.metamodel.schema.MutableRelationship;
import org.eobjects.metamodel.schema.Relationship;
import org.eobjects.metamodel.schema.Schema;
import org.eobjects.metamodel.schema.Table;
import org.eobjects.metamodel.schema.TableType;
import org.eobjects.metamodel.util.FileHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* DataContextStrategy to use for JDBC-compliant databases
*/
public class JdbcDataContext extends AbstractDataContext implements UpdateableDataContext {
public static final String DATABASE_PRODUCT_POSTGRESQL = "PostgreSQL";
public static final String DATABASE_PRODUCT_MYSQL = "MySQL";
public static final String DATABASE_PRODUCT_HSQLDB = "HSQL Database Engine";
public static final String DATABASE_PRODUCT_SQLSERVER = "Microsoft SQL Server";
public static final String DATABASE_PRODUCT_DB2 = "DB2";
private static final Logger logger = LoggerFactory.getLogger(JdbcDataContext.class);
private final FetchSizeCalculator _fetchSizeCalculator;
private final Connection _connection;
private final DataSource _dataSource;
private final TableType[] _tableTypes;
private final String _catalogName;
private final boolean _singleConnection;
/**
* Defines the way that queries are written once dispatched to the database
*/
private IQueryRewriter _queryRewriter;
private String _databaseProductName;
/**
* There are some confusion as to the definition of catalogs and schemas.
* Some databases seperate "groups of tables" by using schemas, others by
* catalogs. This variable indicates whether a MetaModel schema really
* represents a catalog.
*/
private boolean _usesCatalogsAsSchemas;
private String _identifierQuoteString;
private boolean _supportsBatchUpdates;
private boolean _isDefaultAutoCommit;
/**
* Creates the strategy based on a data source, some table types and an
* optional catalogName
*
* @param dataSource
* the datasource objcet to use for making connections
* @param tableTypes
* the types of tables to include
* @param catalogName
* a catalog name to use, can be null
*/
public JdbcDataContext(DataSource dataSource, TableType[] tableTypes, String catalogName) {
this(dataSource, null, tableTypes, catalogName);
}
/**
* Creates the strategy based on a {@link Connection}, some table types and
* an optional catalogName
*
* @param connection
* the database connection
* @param tableTypes
* the types of tables to include
* @param catalogName
* a catalog name to use, can be null
*/
public JdbcDataContext(Connection connection, TableType[] tableTypes, String catalogName) {
this(null, connection, tableTypes, catalogName);
}
/**
* Creates the strategy based on a {@link DataSource}, some table types and
* an optional catalogName
*
* @param dataSource
* the data source
* @param tableTypes
* the types of tables to include
* @param catalogName
* a catalog name to use, can be null
*/
private JdbcDataContext(DataSource dataSource, Connection connection, TableType[] tableTypes, String catalogName) {
_dataSource = dataSource;
_connection = connection;
_tableTypes = tableTypes;
_catalogName = catalogName;
if (_dataSource == null) {
_singleConnection = true;
} else {
_singleConnection = false;
}
// available memory for fetching is so far fixed at 16 megs.
_fetchSizeCalculator = new FetchSizeCalculator(16 * 1024 * 1024);
initialize();
}
/**
* Creates the strategy based on a {@link Connection}
*
* @param connection
* the database connection
*/
public JdbcDataContext(Connection connection) {
this(connection, TableType.DEFAULT_TABLE_TYPES, null);
}
/**
* Creates the strategy based on a {@link DataSource}
*
* @param dataSource
* the data source
*/
public JdbcDataContext(DataSource dataSource) {
this(dataSource, TableType.DEFAULT_TABLE_TYPES, null);
}
/**
* Initializes the data context with global metadata about database type and
* query escaping rules
*/
private void initialize() {
Connection connection = getConnection();
try {
_isDefaultAutoCommit = connection.getAutoCommit();
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "determine auto-commit behaviour");
}
_supportsBatchUpdates = false;
try {
DatabaseMetaData metaData = connection.getMetaData();
_supportsBatchUpdates = supportsBatchUpdates(metaData);
try {
_identifierQuoteString = metaData.getIdentifierQuoteString();
if (_identifierQuoteString != null) {
_identifierQuoteString = _identifierQuoteString.trim();
}
} catch (SQLException e) {
logger.warn("could not retrieve identifier quote string from database metadata", e);
}
_usesCatalogsAsSchemas = usesCatalogsAsSchemas(metaData);
try {
_databaseProductName = metaData.getDatabaseProductName();
logger.debug("Database product name: {}", _databaseProductName);
if (DATABASE_PRODUCT_MYSQL.equals(_databaseProductName)) {
setQueryRewriter(new MysqlQueryRewriter(this));
} else if (DATABASE_PRODUCT_POSTGRESQL.equals(_databaseProductName)) {
setQueryRewriter(new PostgresqlQueryRewriter(this));
} else if (DATABASE_PRODUCT_SQLSERVER.equals(_databaseProductName)) {
setQueryRewriter(new SQLServerQueryRewriter(this));
} else if (DATABASE_PRODUCT_DB2.equals(_databaseProductName)) {
setQueryRewriter(new DB2QueryRewriter(this));
} else if (DATABASE_PRODUCT_HSQLDB.equals(_databaseProductName)) {
setQueryRewriter(new HsqldbQueryRewriter(this));
} else {
setQueryRewriter(new DefaultQueryRewriter(this));
}
} catch (SQLException e) {
logger.warn("Could not retrieve database product name: " + e.getMessage());
}
} catch (SQLException e) {
logger.debug("initialize() threw exception", e);
} finally {
closeIfNescesary(connection);
}
}
private boolean supportsBatchUpdates(DatabaseMetaData metaData) {
try {
return metaData.supportsBatchUpdates();
} catch (Exception e) {
logger.warn("Could not determine if driver support batch updates, returning false", e);
return false;
}
}
private boolean usesCatalogsAsSchemas(DatabaseMetaData metaData) {
boolean result = true;
ResultSet rs = null;
try {
rs = metaData.getSchemas();
while (rs.next() && result) {
result = false;
}
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "retrieve schema and catalog metadata");
} finally {
close(null, rs, null);
}
return result;
}
protected void loadTables(JdbcSchema schema) {
Connection connection = getConnection();
try {
DatabaseMetaData metaData = connection.getMetaData();
// Creates string array to represent the table types
String[] types = getTableTypesAsStrings();
loadTables(schema, metaData, types);
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "retrieve table metadata for " + schema.getName());
} finally {
closeIfNescesary(connection);
}
}
private void loadTables(JdbcSchema schema, DatabaseMetaData metaData, String[] types) {
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();
while (rs.next()) {
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);
}
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "retrieve table metadata for " + schema.getName());
} finally {
close(null, rs, null);
}
}
/**
* Loads primary key metadata for a table
*
* @param table
* @throws MetaModelException
*/
protected void loadPrimaryKeys(JdbcTable table) throws MetaModelException {
Connection connection = getConnection();
try {
DatabaseMetaData metaData = connection.getMetaData();
loadPrimaryKeys(table, metaData);
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "load primary keys");
} finally {
closeIfNescesary(connection);
}
}
/**
* Loads index metadata for a table
*
* @param table
* @throws MetaModelException
*/
protected void loadIndexes(JdbcTable table) throws MetaModelException {
Connection connection = getConnection();
try {
DatabaseMetaData metaData = connection.getMetaData();
loadIndexes(table, metaData);
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "load indexes");
} finally {
closeIfNescesary(connection);
}
}
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(_catalogName, 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 {
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(_catalogName, 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 {
close(null, rs, null);
}
}
/**
* Loads column metadata (no indexes though) for a table
*
* @param table
*/
protected void loadColumns(JdbcTable table) {
Connection connection = getConnection();
try {
DatabaseMetaData metaData = connection.getMetaData();
loadColumns(table, metaData);
} catch (Exception e) {
logger.error("Could not load columns for table: " + table, e);
} finally {
closeIfNescesary(connection);
}
}
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(_catalogName, 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);
final ColumnType columnType = _queryRewriter.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);
}
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "retrieve table metadata for " + table.getName());
} finally {
close(null, rs, null);
}
}
protected void loadRelations(Schema schema) {
Connection connection = getConnection();
try {
Table[] tables = schema.getTables();
DatabaseMetaData metaData = connection.getMetaData();
for (Table table : tables) {
loadRelations(table, metaData);
}
} catch (Exception e) {
logger.error("Could not load relations for schema: " + schema, e);
} finally {
closeIfNescesary(connection);
}
}
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(_catalogName, schema.getName(), table.getName());
}
loadRelations(rs, schema);
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "retrieve imported keys for " + table.getName());
} finally {
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 {
Relationship[] relations = pkTable.getRelationships(fkTable);
boolean exists = false;
for (Relationship relation : relations) {
if (relation.containsColumnPair(pkColumn, fkColumn)) {
exists = true;
break;
}
}
if (!exists) {
MutableRelationship.createRelationship(new Column[] { pkColumn }, new Column[] { fkColumn });
}
}
}
}
public DataSet executeQuery(Query query) throws MetaModelException {
final Connection connection = getConnection();
if (_databaseProductName.equals(DATABASE_PRODUCT_POSTGRESQL)) {
try {
// this has to be done in order to make a result set not load
// all data in memory only for Postgres.
connection.setAutoCommit(false);
} catch (Exception e) {
logger.warn("Could not disable auto-commit (PostgreSQL specific hack)", e);
}
}
ResultSet resultSet = null;
boolean postProcessFirstRow = false;
final Integer firstRow = query.getFirstRow();
if (firstRow != null) {
if (_queryRewriter.isFirstRowSupported()) {
logger.debug("First row property will be treated by query rewriter");
} else {
postProcessFirstRow = true;
}
}
final Statement statement;
try {
statement = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "create statement for query");
}
boolean postProcessMaxRows = false;
Integer maxRows = query.getMaxRows();
if (maxRows != null) {
if (postProcessFirstRow) {
// if First row is being post processed, we need to
// increment the "Max rows" accordingly (but subtract one, since
// firstRow is 1-based).
maxRows = maxRows + (firstRow - 1);
query = query.clone().setMaxRows(maxRows);
logger.debug("Setting Max rows to {} because of post processing strategy of First row.", maxRows);
}
if (_queryRewriter.isMaxRowsSupported()) {
logger.debug("Max rows property will be treated by query rewriter");
} else {
try {
statement.setMaxRows(maxRows);
} catch (SQLException e) {
if (logger.isInfoEnabled()) {
logger.info("setMaxRows(" + maxRows + ") was rejected.", e);
}
postProcessMaxRows = true;
}
}
}
final String queryString = _queryRewriter.rewriteQuery(query);
try {
final int fetchSize = _fetchSizeCalculator.getFetchSize(query);
logger.debug("Applying fetch_size={}", fetchSize);
try {
statement.setFetchSize(fetchSize);
} catch (Exception e) {
// Ticket #372: Sometimes an exception is thrown here even
// though it's contrary to the jdbc spec. We'll proceed without
// doing anything about it though.
logger.warn("Could not setFetchSize on Statement: {}", e.getMessage());
}
logger.debug("Executing query: {}", queryString);
resultSet = statement.executeQuery(queryString);
try {
resultSet.setFetchSize(fetchSize);
} catch (Exception e) {
logger.warn("Could not set fetch size on ResultSet: {}", e.getMessage());
}
DataSet dataSet = new JdbcDataSet(query, this, connection, statement, resultSet);
if (postProcessFirstRow) {
dataSet = new FirstRowDataSet(dataSet, firstRow);
}
if (postProcessMaxRows) {
dataSet = new MaxRowsDataSet(dataSet, maxRows);
}
return dataSet;
} catch (SQLException e) {
// only close in case of an error - the JdbcDataSet will close
// otherwise
close(connection, resultSet, statement);
throw JdbcUtils.wrapException(e, "execute query");
}
}
/**
* Quietly closes any of the parameterized JDBC objects
*
* @param connection
*
* @param rs
* @param st
*/
public void close(Connection connection, ResultSet rs, Statement st) {
closeIfNescesary(connection);
FileHelper.safeClose(rs, st);
}
/**
* Convenience method to get the available catalogNames using this
* connection.
*
* @return a String-array with the names of the available catalogs.
*/
public String[] getCatalogNames() {
Connection connection = getConnection();
// Retrieve metadata
DatabaseMetaData metaData = null;
ResultSet rs = null;
try {
metaData = connection.getMetaData();
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "retrieve metadata");
}
// Retrieve catalogs
logger.debug("Retrieving catalogs");
List catalogs = new ArrayList();
try {
rs = metaData.getCatalogs();
while (rs.next()) {
String catalogName = rs.getString(1);
logger.debug("Found catalogName: {}", catalogName);
catalogs.add(catalogName);
}
} catch (SQLException e) {
logger.error("Error retrieving catalog metadata", e);
} finally {
close(connection, rs, null);
logger.debug("Retrieved {} catalogs", catalogs.size());
}
return catalogs.toArray(new String[catalogs.size()]);
}
/**
* Gets the delegate from the JDBC API (ie. Connection or DataSource) that
* is being used to perform database interactions.
*
* @return either a DataSource or a Connection, depending on the
* configuration of the DataContext.
*/
public Object getDelegate() {
if (_dataSource == null) {
return _connection;
}
return _dataSource;
}
/**
* Gets an appropriate connection object to use - either a dedicated
* connection or a new connection from the datasource object.
*
* Hint: Use the {@link #close(Connection, ResultSet, Statement)} method to
* close the connection (and any ResultSet or Statements involved).
*/
public Connection getConnection() {
if (_dataSource == null) {
return _connection;
}
try {
return _dataSource.getConnection();
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "establish connection");
}
}
private void closeIfNescesary(Connection con) {
if (con != null) {
if (_dataSource != null) {
// closing connections after individual usage is only nescesary
// when they are being pulled from a DataSource.
FileHelper.safeClose(con);
}
}
}
public String getDefaultSchemaName() {
// Use a boolean to check if the result has been
// found, because a schema name can actually be
// null (for example in the case of Firebird
// databases).
boolean found = false;
String result = null;
String[] schemaNames = getSchemaNames();
// First strategy: If there's only one schema available, that must
// be it
if (schemaNames.length == 1) {
result = schemaNames[0];
found = true;
}
if (!found) {
Connection connection = getConnection();
try {
DatabaseMetaData metaData = connection.getMetaData();
// Second strategy: Find default schema name by examining the
// URL
if (!found) {
String url = metaData.getURL();
if (url != null && url.length() > 0) {
if (schemaNames.length > 0) {
StringTokenizer st = new StringTokenizer(url, "/\\:");
int tokenCount = st.countTokens();
if (tokenCount > 0) {
for (int i = 1; i < tokenCount; i++) {
st.nextToken();
}
String lastToken = st.nextToken();
for (int i = 0; i < schemaNames.length && !found; i++) {
String schemaName = schemaNames[i];
if (lastToken.indexOf(schemaName) != -1) {
result = schemaName;
found = true;
}
}
}
}
}
}
// Third strategy: Check for schema equal to username
if (!found) {
String username = metaData.getUserName();
if (username != null) {
for (int i = 0; i < schemaNames.length && !found; i++) {
if (username.equalsIgnoreCase(schemaNames[i])) {
result = schemaNames[i];
found = true;
}
}
}
}
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "determine default schema name");
} finally {
closeIfNescesary(connection);
}
// Fourth strategy: Find default schema name by vendor-specific
// hacks
if (!found) {
if (DATABASE_PRODUCT_POSTGRESQL.equalsIgnoreCase(_databaseProductName)) {
if (_catalogName == null) {
result = "public";
} else {
result = _catalogName;
}
found = true;
}
if (DATABASE_PRODUCT_HSQLDB.equalsIgnoreCase(_databaseProductName)) {
for (int i = 0; i < schemaNames.length && !found; i++) {
String schemaName = schemaNames[i];
if ("PUBLIC".equals(schemaName)) {
result = schemaName;
found = true;
break;
}
}
}
if (DATABASE_PRODUCT_SQLSERVER.equals(_databaseProductName)) {
for (int i = 0; i < schemaNames.length && !found; i++) {
String schemaName = schemaNames[i];
if ("dbo".equals(schemaName)) {
result = schemaName;
found = true;
break;
}
}
}
}
}
return result;
}
/**
* Microsoft SQL Server returns users instead of schemas when calling
* metadata.getSchemas() This is a simple workaround.
*
* @return
* @throws SQLException
*/
private Set getSchemaSQLServerNames(DatabaseMetaData metaData) throws SQLException {
// Distinct schema names. metaData.getTables() is a denormalized
// resultset
Set schemas = new HashSet();
ResultSet rs = metaData.getTables(_catalogName, null, null, getTableTypesAsStrings());
while (rs.next()) {
schemas.add(rs.getString("TABLE_SCHEM"));
}
return schemas;
}
private String[] getTableTypesAsStrings() {
String[] types = new String[_tableTypes.length];
for (int i = 0; i < types.length; i++) {
if (_tableTypes[i] == TableType.OTHER) {
// if the OTHER type has been selected, don't use a table
// pattern (ie. include all types)
types = null;
break;
}
types[i] = _tableTypes[i].toString();
}
return types;
}
public JdbcDataContext setQueryRewriter(IQueryRewriter queryRewriter) {
if (queryRewriter == null) {
throw new IllegalArgumentException("Query rewriter cannot be null");
}
_queryRewriter = queryRewriter;
return this;
}
public IQueryRewriter getQueryRewriter() {
return _queryRewriter;
}
public String getIdentifierQuoteString() {
return _identifierQuoteString;
}
@Override
protected String[] getSchemaNamesInternal() {
Connection connection = getConnection();
try {
DatabaseMetaData metaData = connection.getMetaData();
Collection result = new ArrayList();
if (DATABASE_PRODUCT_SQLSERVER.equals(_databaseProductName)) {
result = getSchemaSQLServerNames(metaData);
} else if (_usesCatalogsAsSchemas) {
String[] catalogNames = getCatalogNames();
for (String name : catalogNames) {
logger.debug("Found catalogName: {}", name);
result.add(name);
}
} else {
ResultSet rs = metaData.getSchemas();
while (rs.next()) {
String schemaName = rs.getString(1);
logger.debug("Found schemaName: {}", schemaName);
result.add(schemaName);
}
rs.close();
}
if (DATABASE_PRODUCT_MYSQL.equals(_databaseProductName)) {
result.remove("information_schema");
}
// If still no schemas are found, add a schema with a null-name
if (result.isEmpty()) {
logger.info("No schemas or catalogs found. Creating unnamed schema.");
result.add(null);
}
return result.toArray(new String[result.size()]);
} catch (SQLException e) {
throw JdbcUtils.wrapException(e, "get schema names");
} finally {
closeIfNescesary(connection);
}
}
@Override
protected Schema getSchemaByNameInternal(String name) {
JdbcSchema schema = new JdbcSchema(name, this);
loadTables(schema);
return schema;
}
public FetchSizeCalculator getFetchSizeCalculator() {
return _fetchSizeCalculator;
}
@Override
public void executeUpdate(final UpdateScript update) {
final JdbcUpdateCallback updateCallback;
if (_supportsBatchUpdates) {
updateCallback = new JdbcBatchUpdateCallback(this);
} else {
updateCallback = new JdbcSimpleUpdateCallback(this);
}
try {
if (isSingleConnection() && isDefaultAutoCommit()) {
// if auto-commit is going to be switched off and on during
// updates, then the update needs to be synchronized, to avoid
// race-conditions when switching off and on.
synchronized (_connection) {
update.run(updateCallback);
}
} else {
update.run(updateCallback);
}
updateCallback.close(true);
} catch (RuntimeException e) {
updateCallback.close(false);
throw e;
}
}
protected boolean isSingleConnection() {
return _singleConnection;
}
protected boolean isDefaultAutoCommit() {
return _isDefaultAutoCommit;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy