/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2016 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* 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.
*
******************************************************************************/
package org.pentaho.di.core.database;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.core.ProgressMonitorListener;
import org.pentaho.di.core.exception.KettleDatabaseException;
import org.pentaho.di.core.logging.LoggingObjectInterface;
import org.pentaho.di.i18n.BaseMessages;
/**
* Contains the schema's, catalogs, tables, views, synonyms, etc we can find in the databases...
*
* @author Matt
* @since 7-apr-2005
*/
public class DatabaseMetaInformation {
private static Class<?> PKG = Database.class; // for i18n purposes, needed by Translator2!!
private String[] tables;
private Map<String, Collection<String>> tableMap;
private String[] views;
private Map<String, Collection<String>> viewMap;
private String[] synonyms;
private Map<String, Collection<String>> synonymMap;
private Catalog[] catalogs;
private Schema[] schemas;
private String[] procedures;
private DatabaseMeta databaseMeta;
public static final String FILTER_CATALOG_LIST = "FILTER_CATALOG_LIST";
public static final String FILTER_SCHEMA_LIST = "FILTER_SCHEMA_LIST";
/**
* Create a new DatabaseMetaData object for the given database connection
*/
public DatabaseMetaInformation( DatabaseMeta databaseMeta ) {
this.databaseMeta = databaseMeta;
}
/**
* @return Returns the catalogs.
*/
public Catalog[] getCatalogs() {
return catalogs;
}
/**
* @param catalogs
* The catalogs to set.
*/
public void setCatalogs( Catalog[] catalogs ) {
this.catalogs = catalogs;
}
/**
* @return Returns the DatabaseMeta.
*/
public DatabaseMeta getDbInfo() {
return databaseMeta;
}
/**
* @param value
* The DatabaseMeta to set.
*/
public void setDbInfo( DatabaseMeta value ) {
this.databaseMeta = value;
}
/**
* @return Returns the schemas.
*/
public Schema[] getSchemas() {
return schemas;
}
/**
* @param schemas
* The schemas to set.
*/
public void setSchemas( Schema[] schemas ) {
this.schemas = schemas;
}
/**
* @return Returns the tables.
*/
public String[] getTables() {
return tables;
}
/**
* @param tables
* The tables to set.
*/
public void setTables( String[] tables ) {
this.tables = tables;
}
/**
* @return Returns the views.
*/
public String[] getViews() {
return views;
}
/**
* @param views
* The views to set.
*/
public void setViews( String[] views ) {
this.views = views;
}
/**
* @param synonyms
* The synonyms to set.
*/
public void setSynonyms( String[] synonyms ) {
this.synonyms = synonyms;
}
/**
* @return Returns the synonyms.
*/
public String[] getSynonyms() {
return synonyms;
}
/**
* @return Returns the procedures.
*/
public String[] getProcedures() {
return procedures;
}
/**
* @param procedures
* The procedures to set.
*/
public void setProcedures( String[] procedures ) {
this.procedures = procedures;
}
public void getData( LoggingObjectInterface parentLoggingObject, ProgressMonitorListener monitor ) throws KettleDatabaseException {
if ( monitor != null ) {
monitor.beginTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.GettingInfoFromDb" ), 8 );
}
Database db = new Database( parentLoggingObject, databaseMeta );
/*
* ResultSet tableResultSet = null;
*
* ResultSet schemaTablesResultSet = null; ResultSet schemaResultSet = null;
*
* ResultSet catalogResultSet = null; ResultSet catalogTablesResultSet = null;
*/
try {
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.ConnectingDb" ) );
}
db.connect();
if ( monitor != null ) {
monitor.worked( 1 );
}
if ( monitor != null && monitor.isCanceled() ) {
return;
}
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.GettingMetaData" ) );
}
DatabaseMetaData dbmd = db.getDatabaseMetaData();
if ( monitor != null ) {
monitor.worked( 1 );
}
if ( monitor != null && monitor.isCanceled() ) {
return;
}
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.GettingInfo" ) );
}
Map<String, String> connectionExtraOptions = databaseMeta.getExtraOptions();
if ( databaseMeta.supportsCatalogs() && dbmd.supportsCatalogsInTableDefinitions() ) {
ArrayList<Catalog> catalogList = new ArrayList<Catalog>();
String catalogFilterKey = databaseMeta.getPluginId() + "." + FILTER_CATALOG_LIST;
if ( ( connectionExtraOptions != null ) && connectionExtraOptions.containsKey( catalogFilterKey ) ) {
String catsFilterCommaList = connectionExtraOptions.get( catalogFilterKey );
String[] catsFilterArray = catsFilterCommaList.split( "," );
for ( int i = 0; i < catsFilterArray.length; i++ ) {
catalogList.add( new Catalog( catsFilterArray[i].trim() ) );
}
}
if ( catalogList.size() == 0 ) {
ResultSet catalogResultSet = dbmd.getCatalogs();
// Grab all the catalog names and put them in an array list
// Then we can close the resultset as soon as possible.
// This is the safest route to take for a lot of databases
//
while ( catalogResultSet != null && catalogResultSet.next() ) {
String catalogName = catalogResultSet.getString( 1 );
catalogList.add( new Catalog( catalogName ) );
}
// Close the catalogs resultset immediately
//
catalogResultSet.close();
}
// Now loop over the catalogs...
//
for ( Catalog catalog : catalogList ) {
ArrayList<String> catalogTables = new ArrayList<String>();
try {
ResultSet catalogTablesResultSet = dbmd.getTables( catalog.getCatalogName(), null, null, null );
while ( catalogTablesResultSet.next() ) {
String tableName = catalogTablesResultSet.getString( 3 );
if ( !db.isSystemTable( tableName ) ) {
catalogTables.add( tableName );
}
}
// Immediately close the catalog tables ResultSet
//
catalogTablesResultSet.close();
// Sort the tables by names
Collections.sort( catalogTables );
} catch ( Exception e ) {
// Obviously, we're not allowed to snoop around in this catalog.
// Just ignore it!
// LogWriter.getInstance().logError(getClass().getName(),BaseMessages.getString(PKG,
// "DatabaseMeta.Error.UnexpectedCatalogError"), e);
}
// Save the list of tables in the catalog (can be empty)
//
catalog.setItems( catalogTables.toArray( new String[catalogTables.size()] ) );
}
// Save for later...
setCatalogs( catalogList.toArray( new Catalog[catalogList.size()] ) );
}
if ( monitor != null ) {
monitor.worked( 1 );
}
if ( monitor != null && monitor.isCanceled() ) {
return;
}
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.GettingSchemaInfo" ) );
}
if ( databaseMeta.supportsSchemas() && dbmd.supportsSchemasInTableDefinitions() ) {
ArrayList<Schema> schemaList = new ArrayList<Schema>();
try {
String schemaFilterKey = databaseMeta.getPluginId() + "." + FILTER_SCHEMA_LIST;
if ( ( connectionExtraOptions != null ) && connectionExtraOptions.containsKey( schemaFilterKey ) ) {
String schemasFilterCommaList = connectionExtraOptions.get( schemaFilterKey );
String[] schemasFilterArray = schemasFilterCommaList.split( "," );
for ( int i = 0; i < schemasFilterArray.length; i++ ) {
schemaList.add( new Schema( schemasFilterArray[i].trim() ) );
}
}
if ( schemaList.size() == 0 ) {
// Support schemas for MS SQL server due to PDI-1531
//
String sql = databaseMeta.getSQLListOfSchemas();
if ( !Utils.isEmpty( sql ) ) {
Statement schemaStatement = db.getConnection().createStatement();
ResultSet schemaResultSet = schemaStatement.executeQuery( sql );
while ( schemaResultSet != null && schemaResultSet.next() ) {
String schemaName = schemaResultSet.getString( "name" );
schemaList.add( new Schema( schemaName ) );
}
schemaResultSet.close();
schemaStatement.close();
} else {
ResultSet schemaResultSet = dbmd.getSchemas();
while ( schemaResultSet != null && schemaResultSet.next() ) {
String schemaName = schemaResultSet.getString( 1 );
schemaList.add( new Schema( schemaName ) );
}
// Close the schema ResultSet immediately
//
schemaResultSet.close();
}
}
for ( Schema schema : schemaList ) {
ArrayList<String> schemaTables = new ArrayList<String>();
try {
ResultSet schemaTablesResultSet = dbmd.getTables( null, schema.getSchemaName(), null, null );
while ( schemaTablesResultSet.next() ) {
String tableName = schemaTablesResultSet.getString( 3 );
if ( !db.isSystemTable( tableName ) ) {
schemaTables.add( tableName );
}
}
// Immediately close the schema tables ResultSet
//
schemaTablesResultSet.close();
// Sort the tables by names
Collections.sort( schemaTables );
} catch ( Exception e ) {
// Obviously, we're not allowed to snoop around in this catalog.
// Just ignore it!
}
schema.setItems( schemaTables.toArray( new String[schemaTables.size()] ) );
}
} catch ( Exception e ) {
// LogWriter.getInstance().logError(getClass().getName(), BaseMessages.getString(PKG,
// "DatabaseMeta.Error.UnexpectedError"), e);
}
// Save for later...
setSchemas( schemaList.toArray( new Schema[schemaList.size()] ) );
}
if ( monitor != null ) {
monitor.worked( 1 );
}
if ( monitor != null && monitor.isCanceled() ) {
return;
}
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.GettingTables" ) );
}
setTables( db.getTablenames( databaseMeta.supportsSchemas() ) ); // legacy call
setTableMap( db.getTableMap() );
if ( monitor != null ) {
monitor.worked( 1 );
}
if ( monitor != null && monitor.isCanceled() ) {
return;
}
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.GettingViews" ) );
}
if ( databaseMeta.supportsViews() ) {
setViews( db.getViews( databaseMeta.supportsSchemas() ) ); // legacy call
setViewMap( db.getViewMap() );
}
if ( monitor != null ) {
monitor.worked( 1 );
}
if ( monitor != null && monitor.isCanceled() ) {
return;
}
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.GettingSynonyms" ) );
}
if ( databaseMeta.supportsSynonyms() ) {
setSynonyms( db.getSynonyms( databaseMeta.supportsSchemas() ) ); // legacy call
setSynonymMap( db.getSynonymMap() );
}
if ( monitor != null ) {
monitor.worked( 1 );
}
if ( monitor != null && monitor.isCanceled() ) {
return;
}
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.GettingProcedures" ) );
}
setProcedures( db.getProcedures() );
if ( monitor != null ) {
monitor.worked( 1 );
}
} catch ( Exception e ) {
throw new KettleDatabaseException(
BaseMessages.getString( PKG, "DatabaseMeta.Error.UnableRetrieveDbInfo" ), e );
} finally {
if ( monitor != null ) {
monitor.subTask( BaseMessages.getString( PKG, "DatabaseMeta.Info.ClosingDbConnection" ) );
}
db.disconnect();
if ( monitor != null ) {
monitor.worked( 1 );
}
}
if ( monitor != null ) {
monitor.done();
}
}
public Map<String, Collection<String>> getTableMap() {
return tableMap;
}
public void setTableMap( Map<String, Collection<String>> tableMap ) {
this.tableMap = tableMap;
}
public Map<String, Collection<String>> getViewMap() {
return viewMap;
}
public void setViewMap( Map<String, Collection<String>> viewMap ) {
this.viewMap = viewMap;
}
public Map<String, Collection<String>> getSynonymMap() {
return synonymMap;
}
public void setSynonymMap( Map<String, Collection<String>> synonymMap ) {
this.synonymMap = synonymMap;
}
}