/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* 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.kie.workbench.common.screens.datasource.management.util;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import org.kie.workbench.common.screens.datasource.management.metadata.CatalogMetadata;
import org.kie.workbench.common.screens.datasource.management.metadata.DatabaseMetadata;
import org.kie.workbench.common.screens.datasource.management.metadata.SchemaMetadata;
import org.kie.workbench.common.screens.datasource.management.metadata.TableMetadata;
import static org.kie.workbench.common.screens.datasource.management.metadata.DatabaseMetadata.DatabaseType.*;
/**
* Utility class for retrieving metadata from a database.
*/
public class DatabaseMetadataUtil {
/**
* Gets the metadata for a given database.
* @param conn A valid connection to the target database.
* @param includeCatalogs If true the database catalogs metadata will be included in the results.
* @param includeSchemas If true the database schemas metadata will be included in the results.
* @return The metadata for the given database.
* @throws Exception if a database error is produced.
*/
public static DatabaseMetadata getMetadata( Connection conn,
boolean includeCatalogs,
boolean includeSchemas ) throws Exception {
try {
DatabaseMetadata result = new DatabaseMetadata( );
ResultSet rs;
DatabaseMetaData sqlMetadata = conn.getMetaData( );
result.setDatabaseType( DatabaseMetadataUtil.getDatabaseType( sqlMetadata.getDatabaseProductName() ) );
result.setDatabaseProductName( sqlMetadata.getDatabaseProductName( ) );
result.setDatabaseProductVersion( sqlMetadata.getDatabaseProductVersion( ) );
result.setDriverName( sqlMetadata.getDriverName( ) );
result.setDriverVersion( sqlMetadata.getDriverVersion( ) );
result.setDriverMajorVersion( sqlMetadata.getDriverMajorVersion() );
result.setDriverMinorVersion( sqlMetadata.getDriverMinorVersion( ) );
if ( includeCatalogs ) {
List< CatalogMetadata > catalogs = new ArrayList<>( );
rs = sqlMetadata.getCatalogs( );
while ( rs.next( ) ) {
catalogs.add( new CatalogMetadata( rs.getString( "TABLE_CAT" ) ) );
}
rs.close( );
result.setCatalogs( catalogs );
}
if ( includeSchemas ) {
List< SchemaMetadata > schemas = new ArrayList<>( );
rs = sqlMetadata.getSchemas( );
while ( rs.next( ) ) {
schemas.add( new SchemaMetadata( rs.getString( "TABLE_CATALOG" ), rs.getString( "TABLE_SCHEM" ) ) );
}
rs.close( );
result.setSchemas( schemas );
}
return result;
} catch ( Exception e ) {
throw new Exception( "It was not possible to read database metadata due to the following error: "
+ e.getMessage( ) );
} finally {
try {
conn.close( );
} catch ( Exception e ) {
//we are not interested in raising this error case.
}
}
}
/**
* Gets a list of database objects metadata for a given database.
* @param conn A valid connection to the target database.
* @param schema A schema name for filtering. A null value will query all the available schemas.
* @param tableNamePattern A table name pattern for filtering the database objects by name, e.g. %INVOICE_%. A null
* value will include all tables.
* @param types A list of database object types for filtering. A null value will include all types.
* @return A list of database objects fulfilling the filtering criteria.
*/
public static List< TableMetadata > findTables( Connection conn,
String schema,
String tableNamePattern,
DatabaseMetadata.TableType... types ) throws Exception {
try {
List< TableMetadata > result = new ArrayList<>( );
DatabaseMetaData sqlMetadata = conn.getMetaData( );
ResultSet rs = sqlMetadata.getTables( null, schema, tableNamePattern, toSqlTypes( types ) );
TableMetadata tableMetadata;
while ( rs.next( ) ) {
tableMetadata = new TableMetadata( rs.getString( "TABLE_CAT" ),
rs.getString( "TABLE_SCHEM" ), rs.getString( "TABLE_NAME" ), rs.getString( "TABLE_TYPE" ) );
result.add( tableMetadata );
}
rs.close( );
return result;
} catch ( Exception e ) {
throw new Exception( "It was not possible to read schema tables due to the following error: " + e.getMessage( ) );
} finally {
try {
conn.close( );
} catch ( Exception e ) {
//we are not interested in raising this error case.
}
}
}
public static DatabaseMetadata.DatabaseType getDatabaseType( String dbProductName ) {
String lowerCasedName = dbProductName.toLowerCase();
if ( lowerCasedName.contains( "h2" ) ) {
return H2;
} else if ( lowerCasedName.contains( "mysql" ) ) {
return MYSQL;
} else if ( lowerCasedName.contains( "mariadb" ) ) {
return MARIADB;
} else if ( lowerCasedName.contains( "postgresql" ) ) {
return POSTGRESQL;
} else if ( lowerCasedName.contains( "oracle" ) ) {
return ORACLE;
} else if ( lowerCasedName.contains( "microsoft" ) && lowerCasedName.contains( "sql" ) && lowerCasedName.contains( "server" ) ) {
return SQLSERVER;
} else if ( lowerCasedName.contains( "db2" ) ) {
return DB2;
}
return null;
}
private static String[] toSqlTypes( DatabaseMetadata.TableType types[] ) {
HashSet< DatabaseMetadata.TableType > typesSet = new HashSet<>( );
String result[] = null;
if ( types != null ) {
for ( int i = 0; i < types.length; i++ ) {
typesSet.add( types[ i ] );
}
}
if ( !typesSet.isEmpty( ) && !typesSet.contains( DatabaseMetadata.TableType.ALL ) ) {
result = new String[ typesSet.size( ) ];
int i = 0;
for ( DatabaseMetadata.TableType type : typesSet ) {
result[ i++ ] = toSqlType( type );
}
}
return result;
}
private static String toSqlType( DatabaseMetadata.TableType type ) {
switch ( type ) {
case TABLE:
return "TABLE";
case SYSTEM_TABLE:
return "SYSTEM TABLE";
case VIEW:
return "VIEW";
case SYSTEM_VIEW:
return "SYSTEM VIEW";
case SEQUENCE:
return "SEQUENCE";
}
return null;
}
}